<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script id="versionArea" type="text/javascript">
//<![CDATA[
var version = {title: "TiddlyWiki", major: 2, minor: 5, revision: 3, date: new Date("Aug 18, 2009"), extensions: {}};
//]]>
</script>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="copyright" content="
TiddlyWiki created by Jeremy Ruston, (jeremy [at] osmosoft [dot] com)

Copyright (c) UnaMesa Association 2004-2009

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.

Neither the name of the UnaMesa Association nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
" />
<!--PRE-HEAD-START-->
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->

<!--PRE-HEAD-END-->
<title> Torpor - release 1.0 Documentation and Usage Guide </title>
<style id="styleArea" type="text/css">
#saveTest {display:none;}
#messageArea {display:none;}
#copyright {display:none;}
#storeArea {display:none;}
#storeArea div {padding:0.5em; margin:1em 0em 0em 0em; border-color:#fff #666 #444 #ddd; border-style:solid; border-width:2px; overflow:auto;}
#shadowArea {display:none;}
#javascriptWarning {width:100%; text-align:center; font-weight:bold; background-color:#dd1100; color:#fff; padding:1em 0em;}
</style>
<!--POST-HEAD-START-->

<!--POST-HEAD-END-->
</head>
<body onload="main();" onunload="if(window.unload) unload();">
<!--PRE-BODY-START-->

<!--PRE-BODY-END-->
<div id="copyright">
Welcome to TiddlyWiki created by Jeremy Ruston, Copyright &copy; 2007 UnaMesa Association
</div>
<noscript>
<div id="javascriptWarning">
This page requires JavaScript to function properly.<br /><br />If you are using Microsoft Internet Explorer you may need to click on the yellow bar above and select 'Allow Blocked Content'. You must then click 'Yes' on the following security warning.
</div>
</noscript>
<div id="saveTest"></div>
<div id="backstageCloak"></div>
<div id="backstageButton"></div>
<div id="backstageArea"><div id="backstageToolbar"></div></div>
<div id="backstage">
	<div id="backstagePanel"></div>
</div>
<div id="contentWrapper"></div>
<div id="contentStash"></div>
<div id="shadowArea">
<div title="MarkupPreHead">
<pre>&lt;!--{{{--&gt;
&lt;link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' /&gt;
&lt;!--}}}--&gt;
</pre>
</div>
<div title="ColorPalette">
<pre>Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
</pre>
</div>
<div title="StyleSheetColors">
<pre>/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected{color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;}
.sparktick {background:[[ColorPalette::PrimaryDark]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity=60)';}
/*}}}*/</pre>
</div>
<div title="StyleSheetLayout">
<pre>/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0 1em 1em; left:0px; top:0px;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0 0; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0;}
.wizardFooter .status {padding:0 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0 0 0.5em;}
.tab {margin:0 0 0 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin:1px 0px;}

.sparkline {line-height:1em;}
.sparktick {outline:0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding:0.1em 0.4em; margin:0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin-left:3em; padding:1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
</pre>
</div>
<div title="StyleSheetLocale">
<pre>/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/</pre>
</div>
<div title="StyleSheetPrint">
<pre>/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/</pre>
</div>
<div title="PageTemplate">
<pre>&lt;!--{{{--&gt;
&lt;div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'&gt;
&lt;div class='headerShadow'&gt;
&lt;span class='siteTitle' refresh='content' tiddler='SiteTitle'&gt;&lt;/span&gt;&amp;nbsp;
&lt;span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div class='headerForeground'&gt;
&lt;span class='siteTitle' refresh='content' tiddler='SiteTitle'&gt;&lt;/span&gt;&amp;nbsp;
&lt;span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id='mainMenu' refresh='content' tiddler='MainMenu'&gt;&lt;/div&gt;
&lt;div id='sidebar'&gt;
&lt;div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'&gt;&lt;/div&gt;
&lt;div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div id='displayArea'&gt;
&lt;div id='messageArea'&gt;&lt;/div&gt;
&lt;div id='tiddlerDisplay'&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!--}}}--&gt;</pre>
</div>
<div title="ViewTemplate">
<pre>&lt;!--{{{--&gt;
&lt;div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'&gt;&lt;/div&gt;
&lt;div class='title' macro='view title'&gt;&lt;/div&gt;
&lt;div class='subtitle'&gt;&lt;span macro='view modifier link'&gt;&lt;/span&gt;, &lt;span macro='view modified date'&gt;&lt;/span&gt; (&lt;span macro='message views.wikified.createdPrompt'&gt;&lt;/span&gt; &lt;span macro='view created date'&gt;&lt;/span&gt;)&lt;/div&gt;
&lt;div class='tagging' macro='tagging'&gt;&lt;/div&gt;
&lt;div class='tagged' macro='tags'&gt;&lt;/div&gt;
&lt;div class='viewer' macro='view text wikified'&gt;&lt;/div&gt;
&lt;div class='tagClear'&gt;&lt;/div&gt;
&lt;!--}}}--&gt;</pre>
</div>
<div title="EditTemplate">
<pre>&lt;!--{{{--&gt;
&lt;div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'&gt;&lt;/div&gt;
&lt;div class='title' macro='view title'&gt;&lt;/div&gt;
&lt;div class='editor' macro='edit title'&gt;&lt;/div&gt;
&lt;div macro='annotations'&gt;&lt;/div&gt;
&lt;div class='editor' macro='edit text'&gt;&lt;/div&gt;
&lt;div class='editor' macro='edit tags'&gt;&lt;/div&gt;&lt;div class='editorFooter'&gt;&lt;span macro='message views.editor.tagPrompt'&gt;&lt;/span&gt;&lt;span macro='tagChooser excludeLists'&gt;&lt;/span&gt;&lt;/div&gt;
&lt;!--}}}--&gt;</pre>
</div>
<div title="GettingStarted">
<pre>To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] &amp; [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: &lt;&lt;option txtUserName&gt;&gt;</pre>
</div>
<div title="OptionsPanel">
<pre>These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser

Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]])

&lt;&lt;option txtUserName&gt;&gt;
&lt;&lt;option chkSaveBackups&gt;&gt; [[SaveBackups]]
&lt;&lt;option chkAutoSave&gt;&gt; [[AutoSave]]
&lt;&lt;option chkRegExpSearch&gt;&gt; [[RegExpSearch]]
&lt;&lt;option chkCaseSensitiveSearch&gt;&gt; [[CaseSensitiveSearch]]
&lt;&lt;option chkAnimate&gt;&gt; [[EnableAnimations]]

----
Also see [[AdvancedOptions]]</pre>
</div>
<div title="ImportTiddlers">
<pre>&lt;&lt;importTiddlers&gt;&gt;</pre>
</div>
</div>
<!--POST-SHADOWAREA-->
<div id="storeArea">
<div title="Advanced Usage" modifier="Paul Tomlinson" created="200911021538" modified="200911301559" changecount="10">
<pre>The basics are useful only for standard [[CRUD]] operations and data validation by type, and while this covers a huge portion of development for the representing objects, it leaves out business logic, extended validation, and the low-level nuts and bolts for getting the most out of the system (and avoiding sneaky gotchas).

In order to help out with those more advanced considerations, here are the following:

* [[Garbage Collection]]: Keeping resource utilization low.
* ''Events'': See [[Extension]].
* [[Exceptions]]: Hints for managing errors states from Torpor.
* [[Extension]]: Adding or tweaking functionality to base classes.
* [[Sessions]]: Considerations for web implementations.
* [[Typed Grids|TypedGrid]]: Advanced Extension using automatically defined named classes.

Previous: [[Examples]]
Next: [[Garbage Collection]] (or [[Appendix]])</pre>
</div>
<div title="Alternatives" modifier="Paul Tomlinson" created="200910312313" modified="200911190014" changecount="2">
<pre>Other PHP ORM abstractions similar to Torpor include:
* [[Doctrine|http://www.doctrine-project.org/]]
* [[Propel|http://propel.phpdb.org/]] (most similar)
* [[Qcodo|http://www.qcodo.com/]]
* [[WikiPedia list of PHP ORM|http://en.wikipedia.org/wiki/List_of_object-relational_mapping_software#PHP]]</pre>
</div>
<div title="Appendix" modifier="Paul Tomlinson" created="200911030624" modified="200911301522" changecount="10">
<pre># Class / Interface References
** [[Column|Class: Column]]
** [[CriteriaBase|Class: CriteriaBase]]
*** [[Criteria|Class: Criteria]]
*** [[CriteriaSet|Class: CriteriaSet]]
** [[DataStore|Interface: DataStore]]
*** [[ANSISQLDataStore|Class: ANSISQLDataStore]]
*** [[MSSQLDataStore|Class: MSSQLDataStore]]
*** [[MySQLDataStore|Class: MySQLDataStore]]
*** [[OracleDataStore|Class: OracleDataStore]]
*** [[SQLiteDataStore|Class: SQLiteDataStore]]
** [[Grid|Class: Grid]]
*** [[DebugGrid|Class: DebugGrid]]
*** [[TypedGrid|Class: TypedGrid]]
** [[GridColumnCollection|Class: GridColumnCollection]]
** [[GridSet|Class: GridSet]]
** [[PersistableContainer|Class: PersistableContainer]]
** [[PersistenceCommand|Class: PersistenceCommand]]
** [[Torpor|Class: Torpor]]
** [[TorporCache|Interface: TorporCache]]
*** [[ThreadCache|Class: ThreadCache]]
*** [[TorporMemcache|Class: TorporMemcache]]
*** [[SessionCache|Class: SessionCache]]
# [[Document Revision|Revision]]
# [[Supported Persistence Engines]]</pre>
</div>
<div title="CRUD" modifier="Paul Tomlinson" created="200911021745" changecount="1">
<pre>An acronym for the 4 main activities of any repository or persistence layer in dealing with a record:
*''C''reate
*''R''ead
*''U''pdate
*''D''elete</pre>
</div>
<div title="ColorPalette" modifier="Paul Tomlinson" created="200910311917" modified="200911071647" changecount="5">
<pre>Background: #fff
Foreground: #000
PrimaryPale: #fc8
PrimaryLight: #f81
PrimaryMid: #b40
PrimaryDark: #410
SecondaryPale: #ffd
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
</pre>
</div>
<div title="Config: Cache" modifier="Paul Tomlinson" created="200911021429" modified="200911030547" changecount="11">
<pre>''Optional.'' At most one entry is allowed, and with a single required {{{class}}} attribute to specify the PHP class which implements the {{{TorporCache}}} interface (one of the few classes to sport a prefix due to the probability of clashing with other common generic names).  This may either be a self-closing tag:

&lt;html&gt;&lt;span style=&quot;font-family: monospace&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Cache&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;class&lt;/font&gt;=&lt;font color=&quot;#ff6060&quot;&gt;&amp;quot;TorporMemcache&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;/span&gt;&lt;/html&gt;
Or contain {{{Parameter}}} entities used to pass named arguments to the {{{Cache}}} class instance:

&lt;html&gt;&lt;span style=&quot;font-family:monospace;&quot;&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Cache&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;class&lt;/font&gt;=&lt;font color=&quot;#ff6060&quot;&gt;&amp;quot;TorporMemcache&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Parameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#ff6060&quot;&gt;&amp;quot;server_192.168.0.100&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;value&lt;/font&gt;=&lt;font color=&quot;#ff6060&quot;&gt;&amp;quot;11211&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Parameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#ff6060&quot;&gt;&amp;quot;ttl&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;10800&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Parameter&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Cache&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/span&gt;&lt;/html&gt;

The {{{name}}} attribute of {{{Parameter}}} entities is required, but the {{{value}}} may either be provided as an attribute or as the interior content between open and closing tags.  This holds true for this same generic {{{Parameter}}} entity wherever it's found.

There is no limit to the number of {{{Parameter}}} entities that can be used, nor restriction on the content of {{{name}}} or {{{value}}} as far as the XML concerned (so long as it fits well-formed constraints - some content may need to be wrapped in {{{&lt;![CDATA[]]&gt;}}} qualifiers).  The meaning of the parameters and their contents is up to the particular {{{Cache}}} class, and should be explained in the corresponding documentation (more information can also be found in the [[Extension]] documentation).

Up: [[Configuration]]
Previous: [[Repository|Config: Repository]]
Next: [[Repository|Config: Repository]] / [[DataStore|Config: DataStore]]</pre>
</div>
<div title="Config: Columns" modifier="Paul Tomlinson" created="200911021434" modified="200911032209" changecount="13">
<pre>Like {{{Grids}}}, the {{{Columns}}} element only serves to contain individual {{{Column}}} entities.

{{{Column}}} entities are the data / field members of the owning {{{Grid}}}.  It also has more attributes than any other element in the entire document (though all but 2 are optional):
&lt;html&gt;&lt;font face=&quot;monospace&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;class&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;PasswordColumn&amp;quot;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;PASSWORD&amp;quot;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;default&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;&amp;quot;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;encoding&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ISO-8859-1&amp;quot;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;generatedOnPublish&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;false&amp;quot;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;length&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;32&amp;quot;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Password&amp;quot;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;nullable&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;false&amp;quot;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;precision&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;0&amp;quot;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;readOnly&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;false&amp;quot;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;varchar&amp;quot;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/html&gt;

Not all of these apply in every situation ({{{precision}}} has no bearing on non-numeric {{{type}}} values, for instance), but there's no harm in providing them in those cases - they will simply be ignored.  {{{Column}}} elements contain no other entities and no simple content (as contained between opening and closing tags).  Only the attributes matter, and their definition is as follows:

!!{{{dataName}}} and {{{name}}}
These follow the same conventions described for {{{//Grid@dataName}}} (see [[Grids|Config: Grids]]), both in construction and meaning to Torpor.

!!{{{class}}}
Default: ''(empty)''
Type: ''string''
Usage: ''optional'' (''required'' if {{{type}}} is set to &quot;''class''&quot;)

This is the PHP class which should be instantiated for this {{{Column}}} when the containing {{{Grid}}} is created.  This will override all other class settings if provided, whether from a {{{DataTypeMap}}} or the overarching {{{ColumnClass}}}.  This must be a valid PHP class name or the special keyword &quot;''none''&quot; which opts the Column out of all {{{DataTypeMap}}} specifications, whereupon it will make use of the global {{{ColumnClass}}} definition.

!!{{{default}}}
Default: ''(empty)''
Type: ''string''
Usage: ''optional''

The contents of &quot;default&quot; will be the initial data value of this column upon instantiation.  Note that this //does// count as a data assignment event and the column //will// be marked as modified for publishing purposes.  This value will also be used if {{{reset()}}} is called on the column, rather than moving all the way to a null value (and will again be marked as having been modified in that state).

!!{{{encoding}}}
Default: ''(empty)''
Type: ''string''
Usage: ''optional''

This specifies the  encoding into which the contents of a string should be translated upon assignment in PHP.  
With no value set, no encoding translation will take place beyond PHP internal defaults, and strlen will be used for all length assessments.  If provided, the ''Multibyte String'' extension must be available to be useful (otherwise the value will be ignored, and an {{{E_USER_WARNING}}} generated), and this value must correspond to one of the values returned by {{{mb_list_encodings()}}}.  All incoming data will be subjected to {{{mb_convert_encoding()}}} to be explicitly set the internal encoding in order to be safe for use with the repository.  Note that in order to be used properly, some encoding types require that the locale be set prior to use and will affect the outcome of the conversion.

!!{{{generatedOnPublish}}}
Default: ''false''
Type: ''boolean''
Usage: ''optional''

Indicates late-binding data, potentially populated only once the record is published to the data store.  This special designation allows the repository adapter to populate the column value, and for Grid objects to associate with one another prior to publishing, maintain that association (this time with data) after publishing, and use it to trace dependencies to publish in a cascade fashion (assuming {{{PublishDependencies}}} is set to true).  It is still possible to manually populate this data as well.  This designation can be used for multiple columns in the same {{{Grid}}}, and columns of any data type.

!!{{{length}}}
Default: ''-1''
Type: ''integer'' (greater than or equal to ''-1'')
Usage: ''optional''

Values less than zero indicate &quot;unlimited.&quot; zero-length strings are essentially useless and not recommended.  This attribute is enforced during assignment in PHP: data beyond this length will be truncated and an {{{E_USER_WARNING}}} will be generated.  If {{{encoding}}} is set and the ''Multibyte String'' extension is available, {{{mb_strlen()}}} is used to measure data length in number of characters; otherwise this will fall back to {{{strlen()}}}, which will almost certainly measure multi-byte strings in bytes instead of characters and may thus result in unintentional truncation for strings of sufficient length that are multi-byte encoding.

This attribute applies only to {{{binary}}}, {{{char}}}, {{{varchar}}}, and {{{text}}} type {{{Column}}} elements.

!!{{{nullable}}}
Default: ''true''
Type: ''boolean''
Usage: ''optional''

This indicates whether the {{{Column}}} may be assigned a literal PHP null.  Note that 0 (zero) or &quot;&quot; (empty string) do not count as null values during assignment.  Regardless of this setting, a newly instantiated Column object (or a linked column to another Column which has not yet been provided with its data) may contain null by virtue of not having yet been assigned.  In order to differentiate between a {{{nullable}}} {{{Column}}} which has not been assigned and one that has been assigned with a null value, the {{{Column::hasData()}}} method may be used.

!!{{{precision}}}
Default: ''0'' (zero)
Type: ''integer'' (signed)
Usage: ''optional''

This only has bearing on numeric {{{Column}}} types, and will simply be ignored in other contexts.  This refers to the number of decimal places OR the order of magnitude available to the data.  Order of magnitude is specified by making this negative (a precision of -2 for example will convert a number like ''12345'' to ''12300'' - with rounding at the point of truncation).  The default value is 0, so it is imperative that this be explicitly set for all floating point numeric data types.  {{{E_USER_WARNING}}} messages will be generated whenever truncation or loss of precision of incoming data occurs.

!!{{{type}}}
Default: ''(none)''
Type: ''enumeration'' (see below)
Usage: ''required''

This describes the data type as it will be represented within PHP.  It is possible, through the use of {{{Column::*PersistData}}} hooks, to support a disconnect between the repository data type and PHP data type.  Examples would include a database column of {{{CHAR(1)}}} or {{{INT}}} being used as a logical boolean, which can be treated within Torpor and PHP as a literal boolean but correctly filter/map back to the database conventions and limitations.  More on this can be found in the [[Extension]] documentation.

There are several different types allowed:
* ''binary:'' validates content byte length only, used to store raw data or file contents
* ''bool:'' literal boolean value, evaluates to/from true/false in PHP
* ''char:'' character/text data of variable encoding
* ''class:'' specifies that a different class will be used to represent this {{{Column}}}, sufficient to perform all necessary validation.  It is not required to have this value for any {{{Column}}} definitions with a {{{class}}} attribute defined. It should only be used when there is no need for extra type-hinted or controlled validation (including content length) outside of what the specified {{{class}}} will provide (which is a required attribute when this is set)
* ''date:'' stores date content in {{{YYYY-MM-DD}}} (PHP {{{date()}}} function argument {{{Y-m-d}}} is equivalent) format (where '-' may be omitted or any one of of {{{, . -}}} or {{{/}}} ).  Note that while structure will be validated, it is possible to specify out of range dates (such as February 31st) that may fail when it reaches the data store.  For full validation and useful utility methods it is highly recommended to wrap this in a {{{Column}}} extending class to expose/provide those features
* ''datetime:''' A concatenation of the {{{date}}} and {{{time}}} validations, separated by a single optional whitespace character
* ''float:'' floating point number, enforced as native {{{float}}} in PHP
* ''integer:'' signed integer number, enforced as native {{{int}}} in PHP
* ''text:'' character/text data of variable encoding, synonymous with char or varchar types
* ''time:'' 24-hour formatted time value with leading zeros, accepting {{{, :}}} or {{{-}}} as the separator: {{{HH:MI:SS}}} (PHP {{{date()}}} function argument {{{H:i:s}}} is equivalent).  Valid times are required, but beyond that there are no native utility operations for manipulating this value or translating it into other formats.  It is highly recommended to wrap this in an extending clss to expose/provide those features.
* ''unsigned:'' unsigned integer number, used as the native PHP {{{int}}} with the addition of the unsigned enforcement (greater than or equal to zero)
* ''varchar:'' character/text data of variable encoding, synonymous with char or text types


Up: [[Configuration]]
Previous: [[Grids|Config: Grids]]
Next: [[Grids|Config: Grids]] / [[Commands|Config: Commands]]</pre>
</div>
<div title="Config: Commands" modifier="Paul Tomlinson" created="200911021435" modified="200911040647" changecount="21">
<pre>The {{{Commands}}} element is yet another simple plural-entity container that has no features or attributes in and of itself, and it is the {{{Command}}} that proves worthwhile.

All qualifying {{{Command}}} entries will be executed by the ~DataStore in the order in which they are defined based on {{{type}}}, and conditionally on {{{context}}}.  This is an operation of the native ~DataStore implementations, but not a hard rule - other extensions or custom classes may implement this differently.

''NOTE:'' this only applies to the generic {{{Delete}}}, {{{Load}}}, and {{{Publish}}} operations.  ~DataStore operations based on custom criteria and the like are still dynamically assembled.  In order to override that behavior individual [[PersistenceCommand|Class: PersistenceCommand]] objects or custom views should be used.

!Attributes
{{{Command}}} has 2 enclosed element types and 2 attributes, only 1 of which is required:
!!{{{type}}}
Default: ''(none)''
Type: ''enumeration: delete, load, publish''
Usage: ''required''

This tells the ~DataStore handler the operations this {{{Command}}} is intended to replace (future releases are planning to support an optional augmentation pattern rather than replacement, which will be backward compatible).  For each of these enumerations the corresponding ~DataStore will rely on this (or these) elements instead.  There may be an unlimited number of {{{delete}}} and {{{publish}}} operations, however only a single {{{load}}} element is supported.  This is enforced within the ~DataStore class rather than the XML, and while this is a limitation of the [[native DataStore handlers|Supported Persistence Engines]] it is not a constraint on their implementation per se - extensions or alternate handlers may work differently.

''NOTE:'' any command returning results are expected to do so according to the Torpor naming conventions for the populated {{{Columns}}}.  Even if the {{{dataName}}} is used, it will still need to be represented in the sanitized key version: {{{UserName}}} or {{{USER_NAME}}} both become {{{USERNAME}}} in this case.  See ''Examples'' below.

!!{{{context}}}
Default: ''(none)''
Type: ''enumeration: all, existing, new''
Usage: ''optional''

This differentiates between the ''Create'' and/or ''Update'' operations (of standard [[CRUD]] options) for any {{{Command}}} where {{{type=&quot;publish&quot;}}}.  {{{new}}} applies only to ''Create'' activity, likewise {{{existing}}} applies only to ''Update'' operations, while ''all'' applies to both equally.  While technically optional, the native ~DataStore adapters examine this values to determine whether or not to include the {{{Command}}} in the list to execute.  An absent attribute will cause it to be omitted.  {{{context}}} is ignored when {{{type}}} is {{{delete}}} or {{{load}}}.

!Elements
!!{{{CommandText}}}
This contains the body of the {{{Command}}} to be executed by the ~DataStore as simple content, which in some cases may make sense to encapsulate as {{{&lt;![CDATA[]]&gt;}}}.  It also maintains 2 optional attributes:
!!!{{{placeholder}}}
Default: ''?''
Type: ''string''
Usage: ''optional''

The {{{placeholder}}} is the generic character found within the {{{CommandText}}} simple content that the ~DataStore will search for when making replacements or insertions based on unnamed {{{CommandParameter}}} elements.
!!!{{{type}}}
Default: ''(none)''
Type: ''string''
Usage: ''optional''

Provided only for convenience, in case the ~DataStore needs to differentiate between invocation styles (SQL versus stored procedures, for example).  There are no pre-set values, and none of the native ~DataStore adapters use this - it is purely for convenience in extension.

!!{{{CommandParameter}}}
An optional, unlimited list of parameters to be combined with the {{{CommandText}}} via named (and/ordered) placeholders to compose the final command and/or its arguments.  This has no content in and of itself and should be treated as a self closing tag with 2 attributes:
!!!{{{column}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

The name of a {{{Column}}} (corresponding to either the {{{dataName}}} or {{{name}}} fo the {{{Column}}}, depending on which has been defined) which is to be the stand-in object (for bind variables) or the source of data (for simple parsing) when the {{{CommandText}}} is evaluated for execution.
!!!{{{placeholder}}}
Default: ''?''
Type: ''string''
Usage: ''optional''

If provided, this is the value which will be replaced (or the point at which the insertion will take place) by the specified {{{column}}} during preparation or execution.  If this is not distinct (such as is the case with the default ''?'' value) it will be inserted at the Nth placeholder corresponding to its order in the list.  If this //is// distinct, the insertion will take place at specifically that location without other qualification.  Note that the native ~DataStore adapters do simple pattern matching and expect but do not force word boundaries, thus is would be unwise to use {{{placeholder}}} values which are potentially sub-strings of other {{{CommandText}}} content.

!Examples
!!!~MySQL, simple order-based explicit placeholder {{{load}}} type
&lt;html&gt;&lt;font style=&quot;font-family: monospace;&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Command&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;load&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;CommandText&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;placeholder&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;?&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Id AS USERID,&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Name AS USERNAME,&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Password AS PASSWORD&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM merged_user_view&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE Id = HEX( ? );&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/CommandText&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;CommandParameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;UserID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Command&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/html&gt;

!!!~MySQL, simple order-based implicit placeholder {{{publish}}} type
&lt;html&gt;&lt;font style=&quot;font-family: monospace;&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Command&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;publish&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;context&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;all&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;CommandText&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;&amp;lt;![&lt;/font&gt;&lt;font color=&quot;#CCCC00&quot;&gt;CDATA&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;[&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;REPLACE INTO users SET&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Id&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = HEX( ? ),&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = ?,&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Password = ?;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;]]&amp;gt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/CommandText&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;CommandParameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;UserID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;CommandParameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;UserName&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;CommandParameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Password&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Command&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/html&gt;

!!!~MySQL, named placeholder {{{publish}}} type of restricted {{{context}}}
&lt;html&gt;&lt;font style=&quot;font-family: monospace;&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Command&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;public&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;context&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;existing&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;CommandText&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;&amp;lt;![&lt;/font&gt;&lt;font color=&quot;#CCCC00&quot;&gt;CDATA&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;[&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UPDATE users SET&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Id&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = HEX( :id ),&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = :name,&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Password = :password&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ON DUPLICATE KEY UPDATE&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Id = Id + VALUE( Id );&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#990000&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;]]&amp;gt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/CommandText&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;CommandParameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;UserID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;placeholder&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;:id&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;CommandParameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;UserName&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;placeholder&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;:name&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;CommandParameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Password&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;placeholder&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;:password&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Command&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/html&gt;

While these examples are ~MySQL specific (and not especially efficient in what they propose to do), they do at least serve to illustrate the utility of being able to specify custom structures and approaches to the ~DataStore internals for repository management, especially when one keeps in mind that multiple {{{delete}}} or {{{publish}}} entries may exist, chaining a series of commands together or acting as virtual triggers.  Stored procedure execution would follow a similar vein as outlined above.

Up: [[Configuration]]
Previous: [[Grids|Config: Grids]] / [[Columns|Config: Columns]]
Next: [[Grids|Config: Grids]] / [[DataTypeMap|Config: DataTypeMap]]</pre>
</div>
<div title="Config: DataStore" modifier="Paul Tomlinson" created="200911021430" modified="200911030704" changecount="17">
<pre>There are 2 possible sets of elements comprising the {{{DataStore}}} definition - either a single {{{DataStore}}} entry, or a pair of {{{ReadDataStore}}} and {{{WriteDataStore}}} elements similar in structure.  This allows for differentiated connection types, which is especially useful in master / slave replication setups.

The {{{type}}} attribute is required and technically unrestricted, though this is intended to correspond with one of the [[natively supported adapter|Supported Persistence Engines]] names:
* ~MySQL
* Oracle (or OCI)
* ~SQLite
* ~SQLServer (or MSSQL)
(as of the 1.0 release)

...or the special value &quot;Custom&quot;, which should be used when a employing a user-defined ~DataStore class. The {{{class}}} attribute is optional unless {{{type}}} is set to &quot;Custom&quot; or any other non-native data store type.  If provided it will override the auto-detection used to map {{{type}}} to the corresponding Torpor ~DataStore class; essentially, {{{type}}} is a shortcut in describing native storage types so you don't have to remember or look up the corresponding class names (or files for inclusion).

No effort will be made to auto load non-native class files; if a Custom class has been requested, it had better exist or be made available via PHP's {{{__autoload}}}.

Interior to the actual {{{DataStore}}} element (regardless of {{{Read}}}, {{{Write}}}, or absent prefixes) are optional simple {{{name}}} / {{{value}}} pair {{{Parameter}}} entities to provide named arguments to the ~DataStore object instance.  The actual names and content of these entries are up to the ~DataStore class being used, and documentation can be found with each in turn (additional useful information can also be found in the [[Extension]] documentation).  {{{//DataStore/Parameter}}} entities (to use the ~XPath notation) feature an additional optional boolean attribute {{{encrypted}}}, which defaults to ''false''.  The intent is to indicate when the {{{value}}} of a {{{Parameter}}} is stored enciphered or otherwise obfuscated, requiring the ~DataStore class to extract the source value before it's actually useful.  This feature is not yet active in native Torpor classes, but is made available here in anticipation of future implementation and to be useful to any user extensions.

{{{DataStore}}} may either be a self-closing tag:

&lt;html&gt;&lt;font face=&quot;monospace&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;DataStore&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;MySQL&amp;quot;&lt;/font&gt;/&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/html&gt;

Or fully populated:

&lt;html&gt;&lt;font face=&quot;monospace&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;ReadDataStore&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;MySQL&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;class&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;MySQLDataStore&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Parameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;host&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;localhost&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Parameter&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Parameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;user&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;value&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;testuser&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Parameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;encrypted&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;true&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;password&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;value&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ac56d8e742&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/ReadDataStore&amp;gt;&lt;/font&gt;&lt;/font&gt;
&lt;/html&gt;


Up: [[Configuration]]
Previous: [[Repository|Config: Repository]] / [[Cache|Config: Cache]]
Next: [[Grids|Config: Grids]]</pre>
</div>
<div title="Config: DataTypeMap" modifier="Paul Tomlinson" created="200911021425" modified="200911051409" changecount="13">
<pre>The {{{DataTypeMap}}} entry is completely optional.  It may be used either as the last entity in [[Options|Config: Options]] where it will apply to every mapped Column type on every Grid, or it may be defined per-Grid or as the second-to-last member of the [[Grid|Config: Grids]] entity.  Its purpose is to instruct Torpor to instantiate every Column of a specific data type as a particular class.  This is especially useful for providing additional handlers, hooks (such as the {{{PersistData}}} hooks), validation, or other generally useful utility routines to particular data types (transparent encryption/decryption is a good example).

Whatever class name is provided here will be created as a new object using the PHP {{{new}}} keyword with the following arguments:
&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$class&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Torpor&amp;nbsp;$torporInstance&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(string)&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$columnName&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;SimpleXML&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$columnXml&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Grid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$grid&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

The intent of these arguments and making changes generally are covered under [[Extension]] in [[Advanced Usage]].  It is generally recommended to inherit from {{{Column}}}, override just what's needed, and otherwise leave the constructor alone.

There are no defaults for {{{DataTypeMap}}} - those provided below are for illustration only.  Any type not appearing here will default to the value of the {{{ColumnClass}}} [[option|Config: Options]].

{{{DataMap}}} entries consist of a PHP class name and the Column data type to which that class name applies.  The same class name may appear multiple times, but only a single mapping per data type is supported.  If multiple are provided, only the last will be used.  The same class may be used multiple times without ill effects.

&lt;html&gt;
&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;DataTypeMap&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;DataMap&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;class&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;DateTime&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;date&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;DataMap&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;class&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;DateTime&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;datetime&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;DataMap&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;class&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;DateTime&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;time&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/DataTypeMap&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;/html&gt;

Up: [[Configuration]]
Previous: [[Options|Config: Options]]
Next: [[Repository|Config: Repository]] or [[Grids|Config: Grids]] / [[Keys|Config: Keys]]</pre>
</div>
<div title="Config: Grids" modifier="Paul Tomlinson" created="200911021432" modified="200911031630" changecount="13">
<pre>The required {{{Grids}}} element's sole purpose is to contain one or more {{{Grid}}} entities.  It has no attributes or other options, and does not matter if there's only one {{{Grid}}}; this is where it goes.

Individual {{{Grid}}} entries are far more interesting:
&lt;html&gt;&lt;font face=&quot;monospace&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Grid&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;class&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;MyUserClass&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;USERS&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;User&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;readOnly&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;false&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;data&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/html&gt;

Of course this isn't much use without [[Columns|Config: Columns]], and not every attribute is required, but this is where we start to get into the substance of the Torpor object factory.  Definitions and requirements of the attributes follow:
!!{{{dataName}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

This is the only required attribute of {{{Grid}}}, used to identify the source of records of this Grid type to the ~DataStore engine.  This will also serve as the object type name in PHP unless {{{name}}} is also provided.

!!{{{class}}}
Default: ''(none)''
Type: ''string''
Usage: ''optional''

A name of a PHP class that will overwrite the {{{GridClass}}} optional value for all instances of this grid, such that whenever new instances are created they will be manufactured as this type of object.  Note that this is not the same as {{{TypedGridClasses}}}, as this class name will not be automatically created by Torpor.  Nor is it required when using {{{TypedGridClasses}}} to place an entry here for every {{{Grid}}} corresponding to the grid-cum-class name, unless you want to override the automatically inferred class name.

!!{{{name}}}
Default: ''(none)''
Type: ''string''
Usage: ''optional''

This is used to differentiate this {{{Grid}}} by something other than the {{{dataName}}} value.  It is recommended that this be a singular name, in order to avoid confusion in the API invocations.  If provided, this is the name by which it will be identified throughout the remainder of the configuration as well: any reference keys identifying this {{{Grid}}} need to use this value.  The Torpor style key, derived from either this or {{{dataName}}}, must be unique among all grids.

Eample: a recommended {{{name}}} value for a {{{Grid}}} with a name like {{{USER_ACCOUNTS}}} would be along the lines of {{{UserAccount}}}, in order to make the instantiation more explicit:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$user_account&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;UserAccount&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$all_accounts&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;UserAccountSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user_account&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newUserAccount&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;etc.&lt;br /&gt;//&amp;nbsp;vs.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user_account&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;UserAccounts&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$all_accounts&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;UserAccountsSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user_account&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newUserAccountsSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;etc.&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Pluralities are very distracting generally.  The new {{{name}}} need not have anything to do with the {{{dataName}}} either - these may be completely differentiated.

!!{{{readOnly}}}
Default: ''false''
Type: ''boolean''
Usage: ''optional''

Indicates that this grid will only be populated by the ~DataStore (and only from {{{&lt;Object&gt;Set}}} operations), and will never be published; attempting to do so will result in an exception).

''This feature is not fully implemented, and is here as a placeholder for future development.''

!!{{{type}}}
Default: ''data''
Type: ''enumeration: data, map''
Usage: ''optional''

Describes whether this {{{Grid}}} will contain pertinent records in their own right, or whether it serves solely as the glue between other {{{Grids}}} in a one- or many- to-many relationships.  Valid values are ''data'' (individual records) or ''map''.  For a ''map'' type Grid, all columns must either comprise the {{{Primary}}} key and be used in some {{{Foreign}}} key definition, or have suitable default values  Only under these circumstances is it possible to automatically maintain the contents based on Torpor activity.

''This feature is not fully implemented, and is here as a placeholder for future development.''


Up: [[Configuration]]
Previous: [[Repository|Config: Repository]] / [[DataStore|Config: DataStore]]
Next: [[Grids|Config: Grids]] / [[Columns|Config: Columns]]</pre>
</div>
<div title="Config: Keys" modifier="Paul Tomlinson" created="200911021436" modified="200911051418" changecount="3">
<pre>Keys are used to define how one {{{Grid}}} may relate to others and the repository.  The main {{{Keys}}} element is simply a container for each of the different individual key types that may defined, and has no options or attributes itself.  It is considered optional, but is highly recommended - a {{{Grid}}} without any {{{Keys}}} defined can only be retrieved by constructing Criteria for searching, and any object that is retrieved will not be able to update.

There are 3 different key types supported:
* [[Foreign|Config: Keys: Foreign]]
* [[Primary|Config: Keys: Primary]]
* [[Unique|Config: Keys: Unique]]

Up: [[Configuration]]
Previous: [[Grids|Config: Grids]] / [[DataTypeMap|Config: DataTypeMap]]
Next: [[Grids|Config: Grids]] / [[Keys|Config: Keys]] / [[Foreign|Config: Keys: Foreign]]</pre>
</div>
<div title="Config: Keys: Foreign" modifier="Paul Tomlinson" created="200911021436" modified="200911051545" tags="example" changecount="15">
<pre>The optional {{{Foreign}}} element has no attributes nor simple-content of its own, and serves only as a container for one or more {{{Key}}} elements here defined.

{{{Foreign}}} type {{{Key}}} entries determine how this {{{Grid}}} can relate to any others that have been defined.  This is done by listing one or more {{{Key}}} elements indicating what {{{Column}}} here refers to what {{{Column}}} on another {{{Grid}}}, and optionally in what context.

For a reference to be viable, all {{{Key}}} elements referring to a target {{{Grid}}} must fully satisfy a unique identification of that {{{Grid}}}.  This is the case when either the {{{Primary}}} definition is fully represented here, or at least one complete {{{Unique}}} key definition.  This includes multiple-column keys: if a referenced {{{Grid}}} has a multi-column {{{Primary}}} key definition, this {{{Grid}}} would require multiple {{{Foreign}}} type {{{Key}}} entries, one per {{{Column}}}, to satisfy the relationships.  Same goes for {{{Unique}}} keys.

Note that this is grouped by context as well: a multi-column reference to another {{{Grid}}} as a particular {{{referenceGridAlias}}} would require that all {{{Key}}} entries share the same {{{referenceGridAlias}}} value.

There is no simple-content (as enclosed between starting and ending tags), and only 4 possible attributes (2 of which are optional).  This should be treated as a self-closing tag.

!Attributes
!!{{{column}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

This must match the {{{dataName}}} (or {{{name}}}, if defined) of a {{{Column}}} on this {{{Grid}}} and indicates the starting point of the reference.

!!{{{referenceColumn}}}
Default: ''(none)''
Type: ''string''
Usage: ''optional''

This must match the {{{dataName}}} (or {{{name}}}, if defined) or a {{{Column}}} on the {{{Grid}}} to which this {{{Key}}} refers.  It is only optional when the source {{{Column}}} and target {{{Column}}} are identically named and so the rest of the relationship can be inferred.

!!{{{referenceGrid}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

This must match the {{{dataName}}} (or {{{name}}}, if defined) of the {{{Grid}}} to which this {{{Key}}} refers.

!!{{{referenceGridAlias}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

One of the more powerful features of Torpor, this allows the referenced {{{Grid}}} to adopt a named context for access.  This means that, for example, an {{{Order}}} object can have a reference key to {{{User}}} without qualification, in which case {{{$order-&gt;getUser();}}} will product a {{{User}}} object, and at the same time may also have a reference key to {{{User}}} with a {{{referenceGridAlias}}} value of {{{Seller}}}, in which case {{{$order-&gt;getSeller();}}} will //also// produce a {{{User}}} object though this time corresponding to the different key (the reciprocal {{{set}}} methods also work in this fashion).

!Examples

These 2 simple {{{Grid}}} definitions show simple relationship definitions, from ''credit'' to ''entity''.  Note that the ''~SourceID'' reference to ''entity.~EntityID'' does //not// include a {{{referenceGridAlias}}} attribute.  This means both that {{{$credit-&gt;getEntity();}}} will automatically use ''~SourceID'' to find the related ''entity'' record, and that {{{$credit-&gt;getSource();}}} will ''//not//'' work because there is no ''source'' type {{{Grid}}} referenced nor alias defined by which to find such an object.

&lt;html&gt;&lt;span style=&quot;font-family: monospace; white-space: nowrap;&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Grid&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;credit&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Columns&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;CreditID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;integer&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;generatedOnPublish&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;true&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;SourceID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;integer&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;RecipientID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;integer&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Amount&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;float&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;precision&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;2&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;DateDeposited&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;date&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Columns&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Keys&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Foreign&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;SourceID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceGrid&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;entity&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceColumn&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;EntityID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;RecipientID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceGrid&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;entity&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceGridAlias&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Recipient&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceColumn&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;EntityID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Foreign&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Primary&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;CreditID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Primary&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Keys&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Grid&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Grid&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;entity&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Columns&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;EntityID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;integer&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;precision&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;10&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;generatedOnPublish&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;true&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Name&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;varchar&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;length&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;50&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;nullable&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;true&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;encoding&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ISO-8859-1&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Description&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;text&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;nullable&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;true&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;length&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;65535&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;encoding&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ISO-8859-1&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Columns&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Keys&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Primary&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;EntityID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Primary&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Keys&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Grid&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;/html&gt;

Automatically available operations from this relationship:

&lt;html&gt;&lt;span style=&quot;color: #000000; font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$entity&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$credit&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getEntity&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$entity&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$credit&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getRecipient&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$entity&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$credit&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newEntity&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$entity&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$credit&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newRecipient&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$credit&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$entity&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newCredit&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$credit&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$entity&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newCreditFromRecipient&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$creditSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$entity&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getCreditSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$creditSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$entity&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getCreditSetFromRecipient&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;



Up: [[Configuration]]
Previous: [[Grids|Config: Grids]] / [[Keys|Config: Keys]]
Next: [[Grids|Config: Grids]] / [[Keys|Config: Keys]] / [[Primary|Config: Keys: Primary]]</pre>
</div>
<div title="Config: Keys: Primary" modifier="Paul Tomlinson" created="200911021437" modified="200911051608" changecount="8">
<pre>The optional {{{Primary}}} element is a simple container with no attributes or simple-content of its own.  It's sole purpose is to hold {{{Key}}} elements which list the {{{Column}}} members of this {{{Grid}}} which comprise a unique identifier.  There is little difference in implementation between {{{Primary}}} and {{{Unique}}} key column lists, except that there may be at most 1 {{{Primary}}} element, and that the {{{Column}}}(s) so appearing here will be used in some short-cut and convenience functions elsewhere.  They also come into prominence for instantiating known TypedGrid objects.

''NOTE:'' No enforcement of the uniqueness of a {{{Primary}}} key is done within Torpor itself, and is solely the responsibility of the repository.  This definition is //logical//, not //practical//, and merely tells the framework that it may rely on this {{{Column}}} list in this fashion.

{{{Primary}}} type {{{Key}}} elements are almost as simple.  They contain no simple-content (as enclosed between start and end tags) and have only a single required attribute:
!!{{{column}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

This must match the {{{dataName}}} (or {{{name}}}, if defined) of a {{{Column}}} on this {{{Grid}}}.

And that's it.  Some simple {{{Grid}}} examples of single- and multiple- column key definitions include:

&lt;html&gt;&lt;span style=&quot;font-family: monospace&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Grid&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;account&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Columns&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;AccountID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;integer&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;generatedOnPublish&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;true&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Name&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;varchar&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;length&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;50&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;encoding&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ISO-8859-1&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Type&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;varchar&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;length&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;8&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;encoding&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ISO-8859-1&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;default&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Checking&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Number&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;varchar&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;length&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;20&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;encoding&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ISO-8859-1&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Description&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;text&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;length&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;65535&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;nullable&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;true&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;encoding&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ISO-8859-1&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Columns&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Keys&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Primary&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;AccountID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Primary&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Unique&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Name&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Unique&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Keys&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Grid&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Grid&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;account_balance&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Columns&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;AccountID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;integer&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;precision&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;10&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Month&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;date&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Balance&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;integer&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;precision&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;10&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Columns&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Keys&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Foreign&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;AccountID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceGrid&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;account&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Foreign&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Primary&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;AccountID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Month&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Primary&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Keys&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Grid&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;/html&gt;

Up: [[Configuration]]
Previous: [[Grids|Config: Grids]] / [[Keys|Config: Keys]] / [[Foreign|Config: Keys: Foreign]]
Next: [[Grids|Config: Grids]] / [[Keys|Config: Keys]] / [[Unique|Config: Keys: Unique]]</pre>
</div>
<div title="Config: Keys: Unique" modifier="Paul Tomlinson" created="200911021438" modified="200911051612" changecount="5">
<pre>The optional {{{Unique}}} elements are a simple container with no attributes or simple-content of its own.  It's sole purpose is to hold {{{Key}}} elements which list the {{{Column}}} members of this {{{Grid}}} which comprise a unique identifier.  There is little difference in implementation between {{{Primary}}} and {{{Unique}}} key column lists, except that there may be as many {{{Unique}}} elements as desired, and {{{Columns}}} may be repeated from one {{{Unique}}} list to the next.

''NOTE:'' No enforcement of the actual {{{Unique}}}-ness of a key is done within Torpor itself, and is solely the responsibility of the repository.  This definition is //logical//, not //practical//, and merely tells the framework that it may rely on a {{{Column}}} list in this fashion.

{{{Unique}}} type {{{Key}}} elements are vary simple.  They contain no simple-content (as enclosed between start and end tags) and have only a single required attribute:
!!{{{column}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

This must match the {{{dataName}}} (or {{{name}}}, if defined) of a {{{Column}}} on this {{{Grid}}}.

That's all there is to it.  Simple examples include:
&lt;html&gt;
&lt;span style=&quot;font-family: monospace; white-space: nowrap;&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Grid&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;user&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Columns&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;integer&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;generatedOnPublish&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;true&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;UserName&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;varchar&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;length&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;50&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;encoding&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ISO-8859-1&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Password&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;varchar&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;length&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;15&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;encoding&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ISO-8859-1&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;GUID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;varchar&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;length&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;64&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;encoding&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ISO-8859-1&amp;quot;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;generatedOnPublish&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;true&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Columns&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Keys&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Primary&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Primary&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Unique&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;UserName&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Password&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Unique&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Unique&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;GUID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Unique&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Keys&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Grid&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;/html&gt;


Up: [[Configuration]]
Previous: [[Grids|Config: Grids]] / [[Keys|Config: Keys]] / [[Primary|Config: Keys: Primary]]
Next: [[Examples]]</pre>
</div>
<div title="Config: Namespace" modifier="Paul Tomlinson" created="200911021424" modified="200911030201" changecount="15">
<pre>Namespaces are a convention of XML used to group elements under a common name.  It is required to be a URI, but not necessarily required to correspond with any real or resolvable address.  The standard convention that has evolved out of convenience is to use a name which identifies the vendor or controller, and often a real location where information (or a schema) describing the format or its associated use can be found online.  Torpor is no exception, using a domain name the [[author|Paul Tomlinson]] had handy which links directly to the schema: http://www.tricornersoftware.com/Products/Torpor/Config/0.1

Within an XML document, this is linked to a namespace prefix by using a standard {{{xmlns}}} prefix as a qualifier (prefixes for prefixes is a little obscure, but a starting point needs to be established somewhere).  In the below example the new namespace declared associated with the URI above is the rather terse {{{trpr}}}; in reality this could be just about anything.  When this namespace prefix is affixed to an element name, it explicitly associates that element with the namespace and its definition.  In the case of the Torpor configuration schema, all of the member elements belong to the root {{{TorporConfig}}} element without any other namespaces or potential ambiguity of where an element might be defined.  Because of this, {{{trpr}}} (or whatever you use) need only be provided for the first element, after which everything else is implied:

&lt;html&gt;
&lt;font face=&quot;monospace&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;?&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;xml&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;version&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;?&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#ff40ff&quot;&gt;trpr&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;TorporConfig&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;version&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;0.1&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;xmlns&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;trpr&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;&lt;a href=&quot;http://www.tricornersoftware.com/Products/Torpor/Config/0.1&quot;&gt;http://www.tricornersoftware.com/Products/Torpor/Config/0.1&lt;/a&gt;&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;/font&gt;
&lt;/html&gt;

Because it's the root element it can define the {{{xmlns}}} to which it belongs at the same time it's invoking it.

The {{{version}}} attribute belongs to the {{{trpr}}} namespace in this example, and is a required attribute of {{{TorporConfig}}}.  It's used to tell Torpor what version of the configuration is in play in order to determine if it is compatible with the current installation and what feature set may be available.  Note that there is not a direct correlation between the Torpor release number and the configuration version number.

It's possible to explicitly declare the schema and its location (not just a namespace which happens to do the same, which doesn't really mean much to the interpreter) using additional XML conventions, but these aren't required unless standalone validation is being performed without explicitly specifying the schema against which the validation should be checked.  The [[repository extraction scripts|Repository Extraction]] scripts use this advanced output by default for convenience, but it doesn't change the standard approach or the schema location against which it is finally validated.

Up: [[Configuration]]
Next: [[Options|Config: Options]]</pre>
</div>
<div title="Config: Options" modifier="Paul Tomlinson" created="200911021425" modified="200911022143" changecount="36">
<pre>Located directly below the {{{&lt;TorporConfig&gt;}}} opening element, {{{Options}}} is one of the  few elements out-of-place with regard to it's order in the alphabet (almost all elements are provided in their alphabetical order for convenience, and will be enforced as such by the schema - deviations from this standard will be noted where they occur).  This is for convenience in editing, since it contains global configuration values that in many ways will dictate the nature of other content in the document.  Putting it in a logical order, easily located at the top of the document, makes a certain amount of sense from this perspective.  Under {{{Options}}}, individual settings are provided using simple-content XML entities where the value is placed between opening and closing tags with no attributes: &lt;html&gt;&lt;span style=&quot;font-family: monospace; white-space: nowrap;&quot;&gt;
&lt;span style=&quot;color:#55C;&quot;&gt;&amp;lt;SampleSetting&amp;gt;&lt;/span&gt;value&lt;span style=&quot;color:#55C;&quot;&gt;&amp;lt;/SampleSetting&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;/html&gt;

These are ordered alphabetically with the next exception of [[DataTypeMap|Config: DataTypeMap]], which is placed at the end of the list so as to avoid visual clutter in editing since it does not follow the simple-content entity standard of all the others.  The {{{Options}}} XML entity output by the [[repository extraction scripts|Repository Extraction]] is a self closing tag ({{{&lt;Options/&gt;}}}) with no values, indicating that defaults will be used for all settings.

!!{{{CacheReferencedGrids}}}
Default: ''true''
Type: ''boolean''

If set to true, when one Grid is used as the source for fetching another related Grid, the source Grid will cache a reference in that context (meaning using any alias name under which the related Grid is fetched) to the resulting object.  This means that not only will repeated calls produce the same Grid record, they will produce it as represented by the the same object reference.  This is a performance enhancement which allows for useful repeat call patterns such as:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;if(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$someGrid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getRelatedRecord&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Load&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;doSomethingTo&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$someGrid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getRelatedRecord&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;);&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Note that it is possible for a single record from the repository to be represented by multiple different object instances, and even in different states as making alteration to one does not propagate to the other.  This behavior is intentional, but comes with a caution of being sure you know what you're doing if you really want more than one.  The {{{PublishAllColumns}}} setting outline below can act as a partial safeguard in these situations as well.

!!{{{CacheReferencedGridSets}}}
Default: ''false''
Type: ''boolean''

Similar in purpose to {{{CacheReferencedGrids}}}, this determines whether or not to do the same with ~GridSet objects.  This is off by default, as the relationship between a Grid and resulting ~GridSet is less tightly coupled than from one Grid to another (examples of the loose coupling include differing Criteria, pagination, or otherwise restricted or qualified sub-set of records that may not always be the intent).

!!{{{ColumnClass}}}
Default: ''Column''
Type: ''string''

This is the PHP class name which will be used as the base prototype for every Grid's Column (unless overridden by [[DataTypeMap|Config: DataTypeMap]] or [[Column|Config: Columns]] settings), and must correspond to a legitimate class name (preferably something which extends Column).

!!{{{Debug}}}
Default: ''false''
Type: ''boolean''

May cause more {{{E_USER_NOTICE}}} events to be produced.  Debug //classes// are a wiser choice, allowing more granularly targeted hooks under user control.

!!{{{GridClass}}}
Default: ''Grid''
Type: ''string''

PHP class name for all Grid prototypes unless overridden per-[[Grid|Config: Grids]] later on.

!!{{{LinkUnpublishedReferenceColumns}}}
Default: ''true''
Type: ''boolean''

This rather long-named option controls whether or not, when using a Grid as a factory for a related Grid, or associating two Grids in a specific context, whether or not to automatically link the corresponding reference Columns between the two in situations where:
# A referenced Column does not currently have data
# That Column has {{{generatedOnPublish}}} set to ''true''
This allows Grid types which have late-binding keys established by the repository to still be associated to one another without having to summarily publish everything just to get that key.  Once established, any request to the source Column for data will be redirected to the now linked target Column to retrieve it's data (if it has any), which will then be stored locally (with the source Column) and finally returned to the calling interface.

Such a pattern allows objects with repository-generated-keys to be associated with one another prior to publishing, which in turn improves performance and prevents partial records from being written to the repository for the sole purpose of generating keys or making some other key-determining round trip (e.g., fetch from a sequence) for resources which may not even be used if the objects are never published.

This has bearing on {{{PublishDependencies}}}: these are the dependencies it's referring to.  If a linked Column is encountered with no data of its own, and the target of that link is {{{generatedOnPublish}}}, that target will be published first and the resulting key propagated to the requesting object. See {{{PerpetuateAutoLinks}}} too.

!!{{{OverwriteOnLoad}}}
Default: ''true''
Type: ''boolean''

Determines when loading an object from the repository whether to overwite any data which was set on the object prior to that fetch or prior to the Grid's ability to load.  When true, any data already set (which does not correspond to the loaded data) will be wiped out.  This will also generate an {{{E_USER_NOTICE}}} warning to indicate somebody's data is going missing, in case this results in aberrant or unexpected behavior.

!!{{{PageSize}}}
Default: ''-1''
Type: ''integer'' (greater than or equal to ''-1'')

The number of records to fetch from the repository for ~GridSet type objects where the local {{{GridSet::setPageSize()}}} has not been explicitly set.  A negative number corresponds to &quot;all available records,&quot; and is not recommended (especially for web apps) unless you really need all records.  However, this is the default in order to avoid nasty surprises in the form of failing to operate on all records matching requested criteria.

!!{{{PermitDDL}}}
Default: ''false''
Type: ''boolean''

Whether or not any data description language (modifications to repository structure) will be permitted.  Disabled by default, and probably only useful if one plans on working with temporary tables and the like.  Whether or not something is DDL is up to the repository handler to figure out, and for that handler to query this setting - it is not pushed to the handler, nor does anything else introspect incoming queries.  General behavior when set to ''false'' is to throw an [[exception|Exceptions]] when DDL is encountered.

!!{{{PerpetuateAutoLinks}}}
Default: ''false''
Type: ''boolean''

Used together with {{{LinkUnpublishedReferenceColumns}}}, this setting indicates whether or not to maintain that linked relationship after data has been retrieved from the target Column.  When set to false, as soon as some data has been retrieved from the target Column the link will be severed and the 2 will go their separate ways.  This is the default, since reference keys between records are not expected to change with sufficient frequency to warrant continuing the link.  If set to true, however, the 2 objects will continue to operate in tandem; useful if keys are expected to be changing for some reason.

''NOTE:'' The source Column data is not pushed to by the target Column; the link relationship is one strictly of pull to source from target when the source Column's data is requested.  Thus it's possible to change the target Column's data many times before the source Column ever wises up.  Just FYI.

!!{{{PublishAllColumns}}}
Default: ''false''
Type: ''boolean''

Determines whether or not to publish all Columns, or just those which have changed since it was loaded.  Applies to loaded Grids only (since all newly created records will be published in their entirety anyway), and is not recommended as ''false'' for use with distributed caching unless {{{ReloadAfterPublish}}} is also ''true'', since the Cache interface is &quot;all or nothing&quot; rather than a delta set.  This feature helps optimize repository performance and can assist in reducing incidental data overwrites at the final repository level in the event that multiple references to the same record are in play at the same time.

If only a few values are changing on a larger Grid object, and especially if this happens with any frequency, there will be a decrease in overall network traffic and database load.  This is most useful in for repositories (or their ~DatatStore adapters) which do not support pre-compiled queries and bind variables for performance,  since it does require that custom queries be assembled and parsed each time which negate any pre-compilation performance gain.  

!!{{{PublishDependencies}}}
Default: ''true''
Type: ''boolean''

If a required Column does not have data, and is linked to a Column which also does not have data but is set to generatedOnPublish, this setting determines whether to publish the linked target Column in order to retrieve its data for use in the source Column we're intending to publish which requires it.  This is a recursive-safe operation in that it will detect circular references, but only in that it will detect them - it will throw an exception rather than segfaulting, and it's up to the calling code to determine how to handle the error.

!!{{{ReloadAfterPublish}}}
Default: ''true''
Type: ''boolean''

Once a Grid has been published, this setting determines whether to mark the Grid as not yet having loaded, such that subsequent requests for data will cause the standard just-in-time load to fire.  Though this slightly decreases performance (by increasing repository communication), it's useful in those circumstances where data may have been altered once it hit the repository (precision truncation, formatting, etc.) in order to ensure everything stays in agreement.  If set to ''false'',however, the data as constituted in that Grid at the moment of publish will persist, both locally and in any Cache configuration.  It is recommended to test the Column data type handling as it corresponds to resulting publish operations in the database to ensure that, in whatever environment you're using things, it all lines up before setting this to ''false'' (which can result in a significant decrease in database load).

''NOTE:'' This has no bearing on {{{generatedOnPublish}}} columns, which will //always// be populated from the repository as a part of the whole publish operation.

!!{{{TypedGridClasses}}}
Default: ''false''
Type: ''boolean''

If set to true, instead of using Torpor's {{{Grid}}} class for all record instances, a new class will be created as an extension to the class {{{TypedGrid}}}.  The new class name will correspond to the sanitized Torpor key name for the Grid (e.g., {{{User}}} becomes {{{USER}}}, {{{order_item}}} becomes {{{ORDERITEM}}}, etc.) - due to PHP case handling these can still be accessed case insensitively for convenience ({{{User}}}, {{{OrderItem}}})

This is most useful in a singleton environment, but can also be used with Torpor as an instance if that instance is passed as an argument in the construction of the object: &lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$torpor&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

''NOTE:'' Torpor must either already have been initialized from the configuration file, or be used with appropriate hooks in the lazy loader ({{{__autoload}}} function) in order for this pattern to be used. See also {{{TypedGridClassesPrefix}}} and [[TypedGrids|TypedGrid]].

!!{{{TypedGridClassesPrefix}}}
Default: ''(empty)''
Type: ''string''

Empty by default, any string used here will be prefixed to the class names constructed when {{{TypedGridClasses}}} is ''true''.  For example, if this contained {{{Torpor}}} and a Grid {{{User}}} was defined, the new class would be named {{{TorporUser}}} (technically {{{TorporUSER}}} due to the key sanitation, but for readability Pascal case is used - class names are thankfully case insensitive in PHP).


Up: [[Configuration]]
Previous: [[Namespace|Config: Namespace]]
Next: [[Options|Config: Options]] / [[DataTypeMap|Config: DataTypeMap]]</pre>
</div>
<div title="Config: Repository" modifier="Paul Tomlinson" created="200911021427" modified="200911030419" changecount="5">
<pre>The {{{Repository}}} element has no attributes or extra values itself, instead serving only as a functional container for the [[Cache|Config: Cache]] and [[DataStore|Config: DataStore]] definitions.

Up: [[Configuration]]
Previous: [[Options|Config: Options]] / [[DataTypeMap|Config: DataTypeMap]]
Next: [[Repository|Config: Repository]] / [[Cache|Config: Cache]]</pre>
</div>
<div title="Configuration" modifier="Paul Tomlinson" created="200911021423" modified="200911301551" changecount="16">
<pre>All configuration files are validated against the {{{TorporConfig.xsd}}} schema to ensure valid structure and content.  If you are unfamiliar with schema validation or XML nuances in general I recommend the excellent [[ZVON.org|http://www.zvon.org/]] resources and tutorials.  If you follow then conventions outlined in this guide you should be just fine regardless.

The smallest successfully validating example is not especially useful:
&lt;html&gt;
&lt;font face=&quot;monospace&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;?&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;xml&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;version&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;?&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#ff40ff&quot;&gt;trpr&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;TorporConfig&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;version&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;0.1&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;xmlns&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;trpr&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;&lt;a href=&quot;http://www.tricornersoftware.com/Products/Torpor/Config/0.1&quot;&gt;http://www.tricornersoftware.com/Products/Torpor/Config/0.1&lt;/a&gt;&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Grids&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Grid&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Example&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Grids&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/&lt;/font&gt;&lt;font color=&quot;#ff40ff&quot;&gt;trpr&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;TorporConfig&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;/font&gt;
&lt;/html&gt;
This is still allowed to pass because the majority of the configuration values are optional.  The above example will allow Torpor to act as a factory for an {{{Example}}} pseudo-class that has no column members, and will not be able to load or publish because there's no [[repository|Config: Repository]] defined (but then, there's no data to load or publish either so that's hardly consequential).

Any option or setting omitted from the XML will use a default setting instead.  These are defined in the schema for those using it to assist in the generation of the configuration file (or to act as a near-at-hand reference and correspond to the default values in the {{{Torpor}}} class.  There is also an included {{{TorporConfig.sample.xml}}} file annotated with the same content found here using inline {{{&lt;!-- XML comments --&gt;}}}.

By default a new {{{Torpor}}} instance (singleton or otherwise) will attempt a just-in-time initialization the first time it's asked to do something that requires an internal data structure.  It will look in the PHP include path for a file name {{{TorporConfig.xml}}}, stopping at the first one it finds, and use that as the basis of operation.  This behavior can be overridden by setting a {{{TORPOR_CONFIG}}} environment variable (containing a file name, URI, or even XML content), or calling the {{{Torpor::initialize()}}} method with an argument specifying the desired XML contents as a string, the name of the configuration file, a file handle, ~SimpleXML instance, or URI.  Regardless of how the XML gets there, it all needs to follow the same rules.

# [[Namespace|Config: Namespace]]
# [[Options|Config: Options]]
## [[DataTypeMap|Config: DataTypeMap]]
# [[Repository|Config: Repository]]
## [[Cache|Config: Cache]]
## [[DataStore|Config: DataStore]]
# [[Grids|Config: Grids]]
## [[Columns|Config: Columns]]
## [[Commands|Config: Commands]]
## [[DataTypeMap|Config: DataTypeMap]]
## [[Keys|Config: Keys]]
### [[Foreign|Config: Keys: Foreign]]
### [[Primary|Config: Keys: Primary]]
### [[Unique|Config: Keys: Unique]]

Previous: [[Getting Started|Getting Started with Torpor]]
Next: [[Namespace|Config: Namespace]] (or [[Examples]])</pre>
</div>
<div title="DefaultTiddlers" modifier="Paul" created="200910311905" changecount="1">
<pre>[[Introduction]]</pre>
</div>
<div title="Downloads" modifier="Paul Tomlinson" created="200910312319" changecount="1">
<pre>Distribution packages are maintained via the [[Torpor Project Page|http://code.google.com/p/torpor-php/]] on [[Google Code|http://code.google.com]]:
* http://code.google.com/p/torpor-php/downloads/list</pre>
</div>
<div title="Examples" modifier="Paul Tomlinson" created="200911061343" modified="200911231500" changecount="41">
<pre>The examples in this section will be done using an explicit instance of Torpor as the basis of all operations.  In the [[Advanced Usage]] section the possibility of object instantiation without this is discussed; though it might simplify the examples to use a similar syntax here, the initial configuration and the caveats surrounding TypedGrid use warrant separate consideration and treatment.  The initialization and instantiation of Torpor in the context shown here is simpler and safer, and so will act as the foundation for these examples.

All these examples assume that one of the following has taken place:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getInstance&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;br/&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

...and that it has been initialized using [[simple_sample.xml]] (with a corresponding database available):

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;initialize&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'simple_sample.xml'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

!!A Note About Keywords
Torpor operations are composed of keywords and modifiers which identify what one is attempting to do, what it's being done to, and the context or manner in which that should be done. This follows a simple syntax such as:
{{{
&lt;verb&gt;&lt;ObjectType&gt;[Set][From&lt;ObjectType&gt;]
}}}

Where {{{&lt;verb&gt;}}} can be any of:
* {{{add}}}
* {{{can}}}*
* {{{get}}}
* {{{is}}}*
* {{{map}}}*
* {{{new}}}
* {{{set}}}
({{{can}}} and {{{is}}}, and {{{map}}} don't follow the full syntactical expansion described above and have their own use cases explored elsewhere).

It is recommended to avoid using keywords in object names solely for the purpose of avoiding confusion; the intended operations can still be performed on the target objects successfully, but only by repeating the keywords in the appropriate places which may make some code less readable.  It's also recommended because while Torpor primitives can assure this kind of correct operation, developer or third-party extensions may not provide the same guarantee.

!!Examples:
# [[The Basics|Examples: Basics]]
# [[Related Objects|Examples: Related Objects]]
# [[Collections and Criteria|Examples: Collections and Criteria]]

Previous: [[Configuration]]
Next: [[The Basics|Examples: Basics]]</pre>
</div>
<div title="Examples: Basics" modifier="Paul Tomlinson" created="200911061529" modified="200911080353" changecount="28">
<pre>All Torpor operations are based on a simple vocabulary that identifies an action, the object(s) on which to perform the action, and any related object to use in that operation.  This applies to both to {{{Grid}}} objects and any {{{Column}}} members.

!!Your First Object
&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

The keyword {{{new}}} is followed by the name of an object type.  This name must correspond to either the {{{name}}} or {{{dataName}}} of a [[Grid|Config: Grids]] entry in the configuration.  While the name must be composed of alphabetic characters only, it's also completely case insensitive, and agnostic to the placement of underscores (which are frequently used in database naming conventions).

Each {{{Grid}}} object has the same basic operations for retrieving, saving, and deleting data:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Load&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Publish&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Delete&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Of these, {{{Publish}}} and {{{Delete}}} are going to be the most useful in terms of implementing code.  The {{{Load}}} operation happens implicitly whenever {{{get}}} is called on any of the member Columns, the object is capable of loading (meaning either the primary key or one or more unique keys have all member columns populated with data), and has not yet been loaded.  {{{Publish}}} predictably stores the object in the repository, {{{Delete}}} removes it (and empties all data out of the object instance), and {{{Load}}} retrieves it based on the identifying criteria inherent in its definition.   The full definition of these methods, their arguments and operations, can be found in the API reference in the [[Appendix]] under ''Class References / [[Grid|Class: Grid]]''.

!!Member Variables
Once we have our object, operating on its data members is easy.  This is a new instance without any default values, so let's try some {{{set}}} operations first:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setUserName&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'harry'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setEmail&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'harry@example.com'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setPasswordHash&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;md5&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'12345'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

We can then retrieve those values using {{{get}}} operations; this time exercising the case insensitivity just for fun:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #007700&quot;&gt;print&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getUSER_NAME&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;print&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;get_email&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;print&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;GET_PASSWORD_HASH&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

It's also possible to use direct object member access syntax to do the same things:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;UserName&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'harry'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Email&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;UserName&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'@xample.com'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;PasswordHash&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;md5&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'12345'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;print_r&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;array(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;USER_NAME&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;EMAIL&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;pAsSwOrD_HaSh&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Again, completely case insensitive and underscore agnostic.  This is because PHP's magic {{{__get}}} and {{{__set}}} functions have been overridden, just as {{{__call}}} has, in order to introspect the request and determine the intended operation.  This even allows for increment and decrement operations and inclusive assignment:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;ID&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;54321&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;ID&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;++;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;ID&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;--;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;ID&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;%=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

There are 2 special extensions to the standard access patterns for {{{Column}}} objects of type {{{boolean}}}.  Assuming that we extended {{{User}}} to include a boolean member variable {{{Active}}}, it would be possible to do the following:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #007700&quot;&gt;if(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;IsActive&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;){&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*...*/&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setActive&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Where the {{{is&lt;ColumnName&gt;()}}} returns the {{{boolean}}} value of the {{{Column}}}, and the {{{set&lt;ColumnName&gt;()}}} method //with no arguments// (and this is critical, in case the italics didn't give it away) will default to {{{true}}}; a literal //null// or otherwise empty variable still counts as an argument and will be evaluated as a {{{boolean}}} in making the assignment.

!!Working with Column Objects
Any time one of the {{{get}}} or {{{set}}} operations is invoked, the Grid object (in this case {{{User}}}) determines the intended operation and its member Column object against which to apply that operation by calling the corresponding method no the Column itself.  Direct developer access to Column objects is also possible and encouraged.  This example shows the {{{Grid::hasColumn()}}} method, the {{{Grid::Column()}}} accessor, and the {{{array}}} style iterator interface, all working with Column objects directly ({{{$user-&gt;$columnName}}} is technically a simple {{{get}}} accessor, but fits well with the example).  Note that the Column object also supports the {{{__toString()}}} magical method, implicitly calling {{{getData()}}} to provide the results:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$columnName&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Id'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;if(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;hasColumn&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$columnName&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$columnName&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Column&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$columnName&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getData&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;foreach(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;as&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$columnName&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$columnObject&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$columnName&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;':&amp;nbsp;'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$columnObject&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getData&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$columnName&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;':&amp;nbsp;'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$columnObject&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;}&lt;span&gt;&lt;/span&gt;&lt;/html&gt;

As a special feature, calling the Column name as a //method// of {{{Grid}}} will also return the underlying {{{Column}}} object:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$aColumn&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Id&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$aColumn&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;UserName&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$aColumn&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Email&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;span&gt;&lt;/span&gt;&lt;/html&gt;

The same rules of case and underscore insensitivity apply.

The full list and definition of Column methods, their arguments and operations, can be found in the API reference in the [[Appendix]] under ''Class References / [[Column|Class: Column]]''.

!!Retrieving Content
Any {{{Grid}}} that has all member {{{Column}}}s of a key (either [[primary|Config: Keys: Primary]] or [[unique|Config: Keys: Unique]]) populated may be retrieved from the repository if a corresponding record exists.  As {{{User}}} has been defined, each of the ID, user name, and email address are considered distinct in their own right.  As a result, if any of these contain data, the full record may be loaded.  Assume we have the following records in the repository:
| !~USER_ID | !~REFERRING_USER_ID | !~USER_NAME | !~EMAIL_ADDRESS | !PASSWORD |h
| 123 | //null// | montreal | montreal@example.com | 5f4dcc3b5aa765d61d8327deb882cf99 |
| 456 | 123 | ottowa | ottowa@example.com | 5ebe2294ecd0e0f08eab7690d2a6ee69 |

The following code:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getUserById&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;456&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$otherUser&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$otherUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setEmail&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'montreal@example.com'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;foreach(&amp;nbsp;array(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$otherUser&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;as&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$userObj&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;USER\n----------\n&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;foreach(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$userObj&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;as&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$columnName&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$column&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;$columnName:&amp;nbsp;$column\n&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

...would produce the following output:
{{{
USER
----------
ID: 456
REFERRINGUSERID: 123
USERNAME: ottowa
EMAIL: ottowa@example.com
PASSWORDHASH: 5ebe2294ecd0e0f08eab7690d2a6ee69

USER
----------
ID: 123
REFERRINGUSERID: 
USERNAME: montreal
EMAIL: montreal@example.com
PASSWORDHASH: 5f4dcc3b5aa765d61d8327deb882cf99

}}}

Useful functions in this regard include {{{Grid::canLoad()}}} and {{{Grid::isLoaded()}}} which can be used to introspect the current state of the object.  Explicit loading can be done via {{{Grid::Load()}}}, which will only actually load an object once no matter how many time's it's called, unless it is forced to refresh by passing {{{true}}} to the {{{Load()}}} method.

!!Saving Content
Saving an object to the repository is the same whether it's a new object, or an existing one that has been changed:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$success&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;if(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;canPublish&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$success&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Publish&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

!!Deleting Content
Any object which returns {{{true}}} from {{{canLoad()}}} has enough identifying criteria to also delete any corresponding record in the repository:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$success&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;if(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;canPublish&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$success&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Delete&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Once done, the {{{$user}}} object will be as empty as if newly created and the repository (and cache, if in use) will have been cleared of the identified record.

!!Errors
Any attempt to access a member variable which does not exist, in any context, will produce a {{{TorporException}}} (which is a simple extension to PHP's built-in {{{Exception}}}, to make containment easier).  This includes {{{get}}} and {{{set}}} operations, {{{Grid::Column()}}} retrieval, or the implicit {{{$user-&gt;Id()}}} &quot;column name as method&quot; syntax.  It's wise to have a default exception handler or wrap Torpor operations in {{{try { /*...*/ } catch( TorporException $e ){ /*...*/ } }}} blocks.  More on this can be found in the [[Exceptions]] section.

Up: [[Examples]]
Next: [[Related Objects|Examples: Related Objects]]</pre>
</div>
<div title="Examples: Collections and Criteria" modifier="Paul Tomlinson" created="200911080354" modified="200911161606" changecount="41">
<pre>Collections in Torpor are referred to as a {{{Set}}}.  These are used to hold zero or more {{{Grid}}} objects of the same type, and may be populated either manually (by adding each one in turn), by retrieving a series of records from the repository, or both.  It supports just-in-time loading using efficient bulk-load operations, and the standard iterator interface for use in {{{foreach}}} loops, and the same advanced relationship operations as individual {{{Grid}}} objects.

!Instantiation
A {{{GridSet}}} (or {{{TypedGridSet}}}, as the case may be) can either be instantiated directly, or through corresponding [[related object|Examples: Related Objects]] factory methods.  The following 2 approaches accomplish exactly the same thing: create a new {{{Order}}} type {{{GridSet}}} object associated with {{{$user}}}.

&lt;html&gt;&lt;span style=&quot;color: #000000&quot;&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getUserById&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;12345&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getOrderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newOrderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

The use of the {{{set&lt;Object&gt;()}}} style methods work here similarly to the related object assignments for individual {{{Grid}}} objects.  Aliases, such as {{{setSeller()}}}, are also valid.  This kind of assignment performs 2 functions:
# Associates the {{{Grid}}} as a constraint for subsequent loading: any retrieval from the repository will correspond to this constraint.
# Any {{{Grid}}} objects already present in the {{{GridSet}}} will be associated with the new {{{Grid}}} according to the context of the {{{set}}} assignment.  Any {{{Grid}}} objects subsequently added (via {{{addGrid()}}} or {{{add&lt;Object&gt;()}}} -- {{{addOrder()}}}, in this case) to the {{{GridSet}}} will //inherit// this association automatically.
Late binding data relationships from {{{generatedOnPublish}}} associated key columns also work as expected.

Note that the syntax for creating a related {{{GridSet}}} is a {{{get&lt;Object&gt;Set()}}} method, rather than a {{{new...}}} method, even if the {{{Grid}}} object being used as the factory is itself new.

A generic {{{GridSet}}} object may also be instantiated and dynamically typed using the {{{GridSet::setType()}}} method, or by adding a {{{Grid}}} object manually: the first {{{Grid}}} in, if the {{{type}}} has not already been explicitly set, will determine the type of the whole {{{GridSet}}}.

!Loading
A {{{GridSet}}} may either be implicitly or explicitly loaded, just as with a {{{Grid}}}.  Implicit load operations will likely be the most common, and take place whenever {{{!GridSet::isLoaded()}}} and {{{GridSet::canLoad()}}} //and// when no {{{Grid}}} objects have manually been added to the set.  This pattern is evoked whenever any of the following calls are used:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$count&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getRecordCount&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;also&amp;nbsp;getGridCount()&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$count&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getTotalRecordCount&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;also&amp;nbsp;getTotalGridCount()&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Typed&amp;nbsp;and&amp;nbsp;Generic&amp;nbsp;names&amp;nbsp;are&amp;nbsp;available:&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getFirstOrder&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getNextOrder&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getFirstGrid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getNextGrid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Iterator&amp;nbsp;interface,&amp;nbsp;not&amp;nbsp;normally&amp;nbsp;called&amp;nbsp;directly&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;reset&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Usually&amp;nbsp;called&amp;nbsp;implicitly&amp;nbsp;like&amp;nbsp;this:&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;foreach(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;as&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*&amp;nbsp;...&amp;nbsp;*/&lt;br /&gt;&lt;/span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Explicit load options include:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$success&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Load&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$success&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;LoadNextPage&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Regardless of which is used, at most {{{GridSet::getPageSize()}}} records will be retrieved from the repository.  For {{{LoadNextPage()}}}, that many //more// records will be retrieved and added to the end of the existing list of records.  This does not {{{rewind}}} the iterator, so continued calls to {{{next}}} will succeed, picking up where it left off:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #007700&quot;&gt;while(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;LoadNextPage&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Page&amp;nbsp;no.&amp;nbsp;'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getPageOffset&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;+&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;--------------------\n&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getNextOrder&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Date&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

!Population
In addition to loading from the repository, {{{Grid}}} objects may be manually added to the Set.  This can be done through 3 different methods that are simple aliases for convenience:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newOrder&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;addGrid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newOrder&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;addOrder&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newOrder&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

The first 2 take a second optional ''boolean'' argument for specifying whether or not the {{{GridSet}}} relationships should also be applied to the new incoming {{{Grid}}} object (defaults to true).  The typed {{{add&lt;Object&gt;}}} method assumes ''true'', and expects all arguments to be {{{Grid}}} objects, allowing for multiple objects to be added at the same time.

There is not currently an explicit mechanism for removing objects from the collection.

!Iteration
There are 3 different mechanisms for iterating through {{{GridSet}}} contents:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;for(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$i&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$i&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;&amp;lt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getRecordCount&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$i&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;++&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getOrder&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$i&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*&amp;nbsp;...&amp;nbsp;*/&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;}&lt;br /&gt;&lt;br /&gt;foreach(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;as&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*&amp;nbsp;...&amp;nbsp;*/&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;}&lt;br /&gt;&lt;br /&gt;while(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getNextOrder&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*&amp;nbsp;...&amp;nbsp;*/&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Each of these will implicitly load a single page if the {{{GridSet}}} has not already loaded, and iterate over the current contents in order of load (based on sort order - see below).

!Pagination
Pagination refers to retrieving data one &quot;page&quot; at a time, or a pre-determined number of records optionally starting at an offset.  This is most likely to be useful within web applications, where only so many records can be effectively displayed on a page, and the interface will be moving between pages.  The number of records on a page can be set either on the {{{GridSet}}} directly by calling {{{GridSet::setPageSize()}}}, or by setting the global {{{PageSize}}} [[configuration option|Config: Options]].  The default is {{{-1}}}, which equates to &quot;unlimited.&quot;  This is rarely convenient however, and is only set to this default in order to avoid risking an even less convenient setting by guessing at the needs of the end user.

The available methods and their operations include:
* {{{GridSet::getTotalRecordCount()}}}: Assuming {{{GridSet::canLoad()}}}, returns the total number of records available in the repository.  Can also be called as {{{GridSet::getTotalGridCount()}}}.
* {{{GridSet::getNumberOfPages()}}}: Using the total record count and current page size, returns the total number of pages (note that the last page may contain between 1 and {{{GridSet::getPageSize()}}} records)
* {{{GridSet::setPageOffset()}}}: Sets the 0-based page offset for the next record fetch; defaults to 0.  Note: this method will not produce an error or warning of the page offset is greater than {{{GridSet::getNumberOfPages() - 1}}}; it will however fail to produce any records at that offset.  Can be retrieved using {{{GridSet::getPageOffset()}}}.
* {{{GridSet::setGridOffset()}}}: Sets a specific grid count (rather than page count) offset in order to start at a more arbitrary point, should you so choose; defaults to 0.  Can be retrieved using {{{GridSet::getGridOffset()}}} - which will also be available after {{{GriSet::setPageOffset()}}} calls, which can be useful in constructing informative text:
&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Showing&amp;nbsp;Orders&amp;nbsp;'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;number_format&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getGridOffset&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;+&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;),&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;0&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'&amp;nbsp;through&amp;nbsp;'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;number_format&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getTotalRecordCount&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(&amp;nbsp;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getPageOffset&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;+&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;*&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getPageSize&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

A nice short example of setting page size and offset is:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$pageNumber&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getUserById&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;12345&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getOrderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;sortBy&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Date&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setPageSize&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;50&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setPageOffset&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pageNumber&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;foreach(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;as&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*&amp;nbsp;...&amp;nbsp;*/&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

''NOTE:'' Calling {{{$order-&gt;getNumberOfPages()}}} does an implicit {{{$order-&gt;getTotalRecordCount()}}}, which causes an implicit load at whatever the current {{{$order-&gt;getPageOffset()}}} may be.  This means that, if you are going to validate the requested page number against the number of available pages, you need to set the page number first.  The count will still return a valid total count regardless of whether there are any records available at the specified offset, this just mitigates the risk of returning both the first (default) page and a subsequently requested page, making the iteration potentially twice as large (and somewhat ambiguous in its contents) as expected.  There is not currently a supported method for retrieving the available record count that does not also load at least 1 page worth of data - sorry about the inconvenience.

In the native {{{DataStore}}} adapters, pagination controls are exercised within the repository for performance.  All page fetches are based on the current sort order - it is recommended that this //not// be changed between successive page loads, or unexpected results (and record duplication) may occur.

!Sorting
The sorting options for a {{{GridSet}}} apply only to the order in which the records will be retrieved from the database, and will not sort the contents of an already loaded (or user populated) {{{Set}}}.  Sorting may be done by any {{{Column}}} of any {{{Grid}}} involved with the loading (see ''Criteria'' below), and certainly by the {{{Grid}}} type of the {{{Set}}} itself.

This introduces one of the advanced aspects of Torpor.  Whereas an individual {{{Grid}}} object has the option to call the {{{Column}}} members in method context to return an object, Torpor provides a similar mechanism for returning the official internal key name of any {{{Grid}}} or its {{{Column}}} members.  Called with a {{{Grid}}} name in a member-fetch {{{get}}} context, it will return the key name of that {{{Grid}}}:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;
Produces:
{{{
ORDER
}}}

The {{{Grid}}} name may be specified using the same case-insensitive and underscore agnostic conventions already established, and will always return the same result.  It also validates the requested {{{Grid}}} name, and will throw a {{{TorporException}}} if it is not found as a member of this instance.

If the same call is made in method context, it will return a {{{GridColumnCollection}}} class which contains all of the {{{Column}}} names for the requested {{{Grid}}}, and which may then in turn be accessed as members (not methods) using the same case-insensitivity (etc.) to produce the official Torpor key name for that {{{Column}}}:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #007700&quot;&gt;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;SellerID&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;
Produces:
{{{
SELLERID
}}}

This has use in sorting because the {{{Column}}} by which to sort the records as retrieved from the repository must be specified in the {{{GridSet::sortBy()}}} will be validated by the Torpor instance to ensure it can be properly constructed into the resulting command by the {{{DataStore}}} for the repository.  If the {{{Column}}} belongs to the same {{{Grid}}} type as the {{{GridSet}}} itself, only that name needs to be provided.  If it is a member of any other {{{Grid}}} type, both the {{{Grid}}} and {{{Column}}} names must be specified.  Or, a literal {{{Column}}} object may be provided in which case the matching {{{Grid}}} and {{{Column}}} names will be extracted.

Thus the range of possible sorting invocations include:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Member&amp;nbsp;Column&amp;nbsp;name&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;sortBy&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Date&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Grid&amp;nbsp;name,&amp;nbsp;Column&amp;nbsp;name&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;sortBy&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;UserName&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Literal&amp;nbsp;Column&amp;nbsp;object&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;sortBy&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Email&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Successive calls to {{{GridSet::sortBy()}}} append the requested sorting specification to the end of the current list.  This may be cleared out at any time by calling {{{GridSet::resetSort()}}}.  The return type of the {{{GridSet::sortBy()}}} method is a reference to the {{{GridSet}}} object itself, which allows for chaining:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Chained&amp;nbsp;sort&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;sortBy&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Date&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;sortBy&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;UserName&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;sortBy&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Email&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

An optional final (either 2nd or 3rd, depending on the context of the method) argument specifies the order of the sort.  This needs to be one of the related {{{GridSet}}} class sort order constants:
* {{{GridSet::ORDER_ASCENDING}}}: Order from lowest to highest (default).
* {{{GridSet::ORDER_DESCENDING}}}: Order from highest to lowest.
* {{{GridSet::ORDER_RANDOM}}}: Random ordering; not all {{{DataStore}}} adapters support this.

Example:
&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;sortBy&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Date&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;GridSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;ORDER_ASCENDING&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

All of these sorting examples have used the {{{$MyTorpor}}} instance as a starting point.  There is also a magical shortcut to providing similar functionality in singleton contexts due to the fact that PHP allows for duplication of keywords between class names and function names, so in addition to the {{{Torpor}}} class there is also a {{{Torpor}}} global function whose sole responsibility is to return the singleton instance of the similar object.  The {{{Grid}}} and {{{Column}}} name examples above could be rewritten as:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;SellerID&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;
Produces:
{{{
ORDER
SELLERID
}}}

It is of course also possible to pass textual names directly in anything that evaluates to a string, and the same rules of case-insensitivity and underscore agnosticism still apply.  These will be validated and exceptions thrown if not recognized - the only reason the {{{Torpor-&gt;&lt;Object&gt;}}} variants are recommended is for tighter control and a preference for not using string literals in implementing code anywhere it may otherwise be avoided.

!Relationships
The whole {{{GridSet}}} may be associated with other {{{Grid}}} objects in any way that the underlying {{{Grid}}} (the type of which the {{{GridSet}}} is) can, allowing for efficient bulk operations.  This means that an entire Set of {{{Order}}} objects may be mapped to the same {{{User}}} at the same time (or more likely, a series of products added to an order - but that's not supported in our simple sample set).  This is done most efficiently using the direct {{{set&lt;Object|Alias&gt;}}} methods, but there are also generic versions for dynamic typing and broader handling:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setSellert&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$otherUser&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setSourceGrid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setSourceGrid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$otherUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Seller'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Both pairs of calls accomplish identical operations in an identical order.  The term {{{source}}} is used when referring to the incoming {{{Grid}}} object because it will act as part of the generated criteria in loading contents from the repository.  These calls will also apply the same assignment in the same context to every {{{Grid}}} currently contained in the set, either assigning associated data or linking reference columns as appropriate based on system settings.  This behavior may optionally be controlled or overridden by passing a ''boolean'' argument to the assignment method - for typed assignments such as {{{setOrder}}} this will be the second argument, whereas for the generic {{{setSourceGrid}}} it will be the third argument, following any alias specification.  If no alias is in use this may be passed as anything which evaluates to ''false''.  A literal ''false'' value isn't a bad idea.

Retrieval of these objects is similar:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$otherUser&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getSeller&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getSourceGrid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'User'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$otherUser&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getSourceGrid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Seller'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Calling {{{get&lt;Object&gt;}}} as a typed name where the object does not exist will throw a {{{TorporException}}}.  Calling {{{getSourceGrid}}} for an unknown or unassigned {{{Grid}}} will return ''false''.

!Criteria
Any source grid (see {{{Relationships}}} above) implicitly become part of the criteria used to retrieve records from the repository.  While this is useful, it's often not restrictive enough, in that a smaller subset of records is desired, such as those which correspond to a certain date range or shipping type (in our {{{Order}}} example), etc.

Torpor supports a broad range of {{{Criteria}}} objects to provide this functionality, which {{{Criteria}}} may apply to any data member of the {{{Grid}}} type being retrieved, or of any {{{Grid}}} that references it or can be referenced by it.  The comparison values or restrictions may be negated, and/or compared to other {{{Column}}} values within the repository rather than passing the value in directly.  The full range of {{{Criteria}}} types, their arguments and settings, is covered in the [[Appendix]] under ''Class References /'' [[Criteria|Class: Criteria]].

The first argument during creation of a {{{GridSet}}} class may be either a {{{Criteria}}} or {{{Criteria...Set}}} object.  These may also be added after the fact using either the {{{GridSet::setSourceCriteria()}}} or {{{GridSet::addCriteria()}}} methods, which either overwrite or append.  All {{{Criteria}}} added using {{{GridSet::addCriteria()}}} are done so in an ''AND'' context; if this is not the desired behavior, wrap these in a {{{CriteriaOrSet}}} and then add that instead.  Note that all {{{Criteria}}} related operations should be completed before the first loading attempt is made: setting {{{Criteria}}} after the fact will not restrict the populated record set in any way, and in some instances may throw an exception.

All {{{Criteria}}} may also be optionally grouped in either a {{{CriteriaAndSet}}} or {{{CriteriaOrSet}}}, which indicate that &quot;//all// {{{Criteria}}} must match&quot; or &quot;//any// {{{Criteria}}} must match&quot; respectively to qualify a repository record for retrieval.  These may themselves be grouped into {{{Criteria...Set}}} collections, allowing for construction of complex and nuanced logic using simple operations:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;addCriteria&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;CriteriaBetween&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Date&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'2009-04-09'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'2009-12-12'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;true&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;&quot;inclusive&quot;&amp;nbsp;search&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;addCriteria&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;CriteriaAndSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;CriteriaOrSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;CriteriaContains&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Email&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'real'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;case&amp;nbsp;sensitive&amp;nbsp;by&amp;nbsp;default!&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;CriteriaContains&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Email&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'tow'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;true&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;case&amp;nbsp;insensitive&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;CriteriaNotEndsWith&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Email&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'aol.com'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;true&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;case&amp;nbsp;insensitive&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&lt;br /&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

According to this logic, {{{$orderSet}}} will only retrieve {{{Order}}} objects that:
# Have a {{{Date}}} from 09-Apr-2009 BCE through 12-Dec-2009 BCE, inclusive
# AND are associated with a {{{User}}} that:
## Has an email address containing either &quot;real&quot; (case sensitive) OR &quot;tow&quot; (case insensitive) - the &quot;montreal&quot; and &quot;ottowa&quot; examples from [[The Basics|Examples: Basics]] match.
## AND has an email address that does not end in &quot;aol.com&quot; (case insensitive).

By default, {{{Criteria}}} use the same case-sensitive string comparison as provided by PHP (where supported by the underlying {{{DataStore}}}, which almost all do).  This differs from most string comparison collations in most modern RDBMS implementations, but should lessen the learning curve for approaching Torpor from a PHP perspective in that it matches built-in comparison and sorting operations.

Note that because the various {{{Criteria}}} objects do not belong to the {{{OrderSet}}} directly that both the {{{Grid}}} type name and the member {{{Column}}} name must be supplied in order to indicate to which object these belong (unlike sorting operations, which can assume the {{{Grid}}} type as a starting point).  Any {{{Grid}}} used in the assembly of any {{{Criteria}}} assigned to the {{{GridSet}}} may be used as a specification in {{{GridSet::sortBy()}}}.

Any related {{{Grid}}} objects (from ''Relationships'' above, or from which the {{{GridSet}}} was first created such as in ''Instantiation'' above) will also be part of the resulting criteria assembly used by the {{{DataStore}}} for retrieval from the repository.  The biggest difference is that related {{{Grid}}} objects also provide the implicit assignment capacity to all incoming {{{Grid}}} objects, whereas {{{Criteria}}} are used only to restrict retrieval.

Up: [[Examples]]
Previous: [[Related Objects|Examples: Related Objects]]
Next: [[Advanced Usage]]</pre>
</div>
<div title="Examples: Related Objects" modifier="Paul Tomlinson" created="200911071429" modified="200911091434" changecount="41">
<pre>Torpor's biggest strength comes not from its automation of [[CRUD]] operations, but its ability to intelligently associate related objects to one another based on the [[foreign key|Config: Keys: Foreign]] mapping in the configuration file.  Any {{{Grid}}} that references or is referenced by any other {{{Grid}}} can be used as a factory to fetch existing or create new instances and records.

This relationship is defined entirely within the XML: whether or not the underlying structure actually supports or enforces foreign references, so long as the configuration file has the right [[foreign keys|Config: Keys: Foreign]] described everything in this section will work.

A word of caution: related object fetches //always// work; that is, they always return a {{{Grid}}} object of the appropriate type, and match up any related values between the objects.  That does not mean that the new object is capable of loading (if the column thus referencing it is //null//, for example) or will be populated with any data.  It's up to the implementing code to make a determination whether or not the new object is viable (the {{{canLoad()}}} method is a good candidate for that).

A second word of caution: Torpor doesn't do anything about relationships when an object is deleted.  For those repositories which support and enforce foreign keys this can get messy very quickly - anything still referring to the object to be deleted will prevent the delete attempt from succeeding, and in fact produce an exception.  It is recommended that this be worked out one of two ways:
# Have appropriate delete handling components in the repository (such as {{{ON DELETE CASCADE}}})
# Override the {{{OnBeforeDelete}}} event of a {{{Grid}}} and manually execute such a cascade by deleting associated collections (performance sucks, but this will also work for those repositories which do have have explicit relationship handling [such as ~MyISAM tables in ~MySQL])

!!~One-to-One Fetch
The relationships defined for {{{Order}}} (see [[simple_sample.xml]]) indicate that it maps directly to {{{User}}} based on primary key.  Because of this, {{{Order}}} can refer to at most a single {{{User}}} object (at least in {{{User}}} context; see below for alias handling), and can be used to fetch a single {{{Grid}}} object matching that description.

This makes sense not only from a convenience perspective, but also in terms of safe enforcement of operations.  The following is perfectly valid code:

&lt;html&gt;&lt;span style=&quot;font-family: monospace&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getOrderById&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;15243&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setId&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getUserId&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

But it's not especially pleasant.  It requires manual instantiation of the new object type and explicit population of the related keys; in contexts where multi-column keys are in use this gets tedious very quickly.  The preferred method of the above is:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getOrderById&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;15243&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

This is a special use of the {{{get}}} operation.  The Torpor code determines that a {{{get}}} is desired and analyzes the suffix to determine that we're getting something //other// than a {{{Column}}} belonging to this {{{Grid}}} (which means that it is the user's/developer's responsibility to ensure that no {{{Column}}} entries share names with related {{{Grid}}} objects; it's an unlikely collision, but you have been warned), and seeks to determine if the requested object is known to Torpor and a component of the relationships defined for this {{{Grid}}}.  If not, it will throw a {{{TorporException}}}; otherwise, it will pass the call up the stack to the main Torpor instance and request that a {{{Grid}}} matching the description and the association criteria be produced.  No {{{Key}}} columns need be explicitly populated, and out pops our {{{User}}} object on the other end.

Assuming {{{CacheReferencedGrids}}} is set to {{{true}}} in the [[configuration|Config: Options]], {{{Order}}} will also have an internal member variable set aside for {{{User}}}, and repeated calls to {{{getUser()}}} will return the exact same object instance every time.

!!Using Aliases
{{{Order}}} has a second mapping to {{{User}}}, this time with the {{{referenceGridAlias}}} attribute set to {{{Seller}}}.  This setting provides an alternate name (or context) for this relationship, which is reflected in the invocation pattern:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getOrderById&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;15243&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getSeller&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Again with a special {{{get}}} operation, and this time it's for something other than a {{{Column}}} as well as a any known {{{Grid}}} object; but it //does// match the {{{referenceGridAlias}}} setting, that tells us the {{{Key}}} columns involved and ultimately the type of underlying {{{Grid}}} to fetch.

The {{{User}}} object makes a similar reference, this time to itself:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$userToo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getReferringUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Something like this makes it possible to traverse a hierarchy with a simple loop:

&lt;html&gt;&lt;span style=&quot;font-family: monospace&quot;&gt;
&lt;span style=&quot;color: #007700&quot;&gt;while(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getReferringUserId&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getReferringUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Note however that this is ''A.'' not very efficient since a repository fetch operation must take place for every object, which then hangs around in memory (see [[Garbage Collection]] in the [[Advanced Usage]] section), and ''B.'' provides no protection against recursion.  The former can be solved in part with a temporary object and an explicit {{{destroy()}}} call, but the latter will require maintaining an identifying list of the {{{Id}}} values traversed to ensure we halt if we encounter a duplicate.

Very few repositories natively support hierarchical queries, and while Torpor does [[support|Supported Persistence Engines]] the data engines themselves, it has no mechanisms for the retrieval of hierarchical data as yet.  Just FYI.

!!Assignment
As is typical, assignment works in the reverse of retrieval, making use of the {{{set}}} keyword in place of {{{get}}}.  It's a simple practice to assign two objects to one another, where Torpor will set all appropriate {{{Column}}} data between the two based on the relationship:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setReferringUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$userToo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setSeller&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$userToo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Note that aliases continue to work in these methods as well.

An inevitable question in this type of pattern is, &quot;What about new objects?&quot;  In most modern persistence layers the {{{Primary}}} key of any record is coupled with the repository itself, and is usually not available until after the object has been {{{Publish()}}}'d.  In Torpor, this is indicated by setting a {{{Column}}}'s {{{generatedOnPublish}}} attribute to {{{true}}}.  This allows us to treat it as though it will eventually have data and maintain the intended relationships even if it's between identities just now (but it's prospects will pick up in the future, it swears).  In order for this to work, the global {{{LinkUnpublishedReferenceColumns}}} must also be set to {{{true}}} (which is also the default):

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newOrder&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;span&gt;&lt;/span&gt;&lt;/html&gt;

This works.  A call to {{{$order-&gt;getUser()}}} will return our selfsame {{{User}}} object.  However, a call to {{{$order-&gt;getUserId()}}} will return //null//, because it does not yet have data.  The important thing here is that the //null// it returns belongs to {{{User}}}; because the reference columns have been linked, {{{$order-&gt;UserId}}} implicitly pulls data from {{{$user-&gt;Id}}} to get its answer.  When it has no data as well, //null// is returned.  If, however, it has been populated (through whatever means), then not only does {{{$order-&gt;UserId}}} retrieve that new data but it also sets it for itself and severs the automatic link between the two (assuming that the data is unlikely to change there's no reason to keep redirecting; this can be overridden by setting {{{PerpetuateAutoLinks}}} to {{{true}}}; more information about column-linking can be found in the [[Appendix]] under ''Class References / [[Column|Class: Column]]'').

More importantly, not only does it work, but assuming that the {{{PublishDependencies}}} option is set to {{{true}}} (default), calling {{{$order-&gt;Publish()}}} will flush the entire thing to the repository in the necessary order to satisfy those late-binding data assumptions.  This kind of operation //is// recursive safe - if recursion is detected in the process a {{{TorporException}}} will be thrown and the process aborted.  A similar exception will also be thrown if one of the items in the dependency hierarchy cannot publish (lacking required data members, for example).

!!Factories
Instead of manually creating new objects to associate with one another, just as with the fetch ({{{get}}}) and assignment ({{{set}}}) operations it's possible to create new objects from the relationships themselves ({{{new}}}):

This works from both sides of a &quot;one-to-many&quot; relationship such as we've already been using:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newSeller&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$userToo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newReferringUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;br/&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$userToo&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newUserFromReferringUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;br/&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newOrder&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newOrderFromSeller&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Note that the use of aliases is supported here as well.  In addition to the {{{new}}} keyword, we have also introduced the {{{From}}} modifier keywork.  Since a {{{User}}} type {{{Grid}}} will always be typed as a {{{User}}}, the way to indicate that it should be treated in the {{{Seller}}} context for the creation of a new {{{Order}}} is by concatenating the modifier and the alias-context together: {{{...FromSeller}}}.  Technically it would also be possible to say {{{newOrderFromUser}}}, in case that level of redundancy were desired; however, since the {{{Order}}} -- {{{User}}} relationship is already defined without alias-context qualifier this is purely optional. 

For all objects created using the {{{new}}} methods, those which already contain the referring data will be assigned over to the related columns in the new object automatically.  Those without data, marked as {{{generatedOnPublish}}}, with the global {{{LinkUnpublishedReferenceColumns}}} option set to {{{true}}}, will be associated as linked dependencies just as in the prior example.

!!Sets (~One-to-Many Fetch)
So far all of our examples have dealt with single objects, where the corresponding object on the other side of the operation was unambiguous.  Since we're dealing with one-to-many relationships however, it only makes sense to explore the retrieval of object collections.  A collection of objects in Torpor is referred to as a {{{Set}}}, and is instantiated as a {{{GridSet}}} object (or {{{TypedGridSet}}}, if {{{TypedGridClasses}}} are enabled).  This is not to be confused with the {{{set}}} assignment verb, which will only ever take place at the very beginning of a method name.  As referring to a collection, {{{Set}}} will always follow a {{{Grid}}} object name qualifier or alias:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getOrderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getOrderSetFromSeller&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$userToo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getUserSetFromReferringUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

In these examples, not only are aliases supported, but the {{{From}}} modifier can also be used as with the prior examples.  Creation or retrieval of a {{{Set}}} is only supported from the &quot;one&quot; side of a &quot;one-to-many&quot; relationship; {{{$order-&gt;getUserSet()}}} will produce an exception.

The use and treatment of collections is covered more extensively in the [[next|Examples: Collections and Criteria]] section, which contain examples for retrieving and manipulating the contents as well as restricting them to specific subsets.

Up: [[Examples]]
Previous: [[The Basics|Examples: Basics]]
Next: [[Collections and Criteria|Examples: Collections and Criteria]]</pre>
</div>
<div title="Exceptions" modifier="Paul Tomlinson" created="200911190107" modified="200911231741" changecount="9">
<pre>Torpor really likes exceptions, and uses them all over the place whenever it encounters a situation beyond which it cannot reasonably proceed.  In standard practice these should be unlikely, though during active development they can occur quite regularly as the kinks are worked out.  Regardless of whether you actually expect them, expect them, and handle them correctly.  This can be done either by wrapping everything in {{{try}}}/{{{catch}}} blocks, or by ensuring a default exception handler has been registered.

It is always a good idea to catch exceptions, using whatever mechanism you feel appropriate, or at the very least Never Showing Your Errors On the Front End; especially where descriptive error messages are used these can be at the very least unprofessional, and at the worst provide information about the underlying operation of the code or the repository which can be used in attacks.

The error messages provide by Torpor try to be verbose enough that it's easy to determine exactly what the code was attempting to do when it encountered the error.  It will indicate the type of {{{Grid}}} and operation in question, and the stack trace will let you know the exact lines in each of the files on the stack through which that operation passed before encountering its demise.  As is the case with most frameworks, there is even some abstraction in place when it comes to throwing exceptions in order to leverage a standardized routine.  This usually means that the last few lines (depth-wise) in the stack will be the result of those methods and can readily be ignored:
{{{
Could not connect to MySQL using supplied credentials: Can't connect to MySQL server on '127.0.0.1'
#0 /torpor-php/src/ANSISQLDataStore.php(408): Torpor::throwException('Could not conne...')
#1 /torpor-php/src/MySQLDataStore.php(111): ANSISQLDataStore-&gt;throwException('Could not conne...')
#2 /torpor-php/src/MySQLDataStore.php(131): MySQLDataStore-&gt;connect()
#3 /torpor-php/src/MySQLDataStore.php(310): MySQLDataStore-&gt;getConnection()
#4 /torpor-php/src/MySQLDataStore.php(315): MySQLDataStore-&gt;escape('ORDER', true, '`')
#5 /torpor-php/src/ANSISQLDataStore.php(678): MySQLDataStore-&gt;escapeDataName('ORDER')
#6 /torpor-php/src/ANSISQLDataStore.php(230): ANSISQLDataStore-&gt;CriteriaToSQL('ORDER', Object(CriteriaAndSet), Array)
#7 /torpor-php/src/Torpor.php(1152): ANSISQLDataStore-&gt;LoadSet(Object(Orderset), false)
#8 /torpor-php/src/GridSet.php(205): Torpor-&gt;Load(Object(Orderset), false)
#9 torpor-php/src/GridSet.php(528): GridSet-&gt;Load()
#10 /torpor-php/src/test/example.php(56): GridSet-&gt;rewind()
#11 {main}
}}}

Line 56 from the mythical {{{example.php}}}:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*&amp;nbsp;...&amp;nbsp;*/&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;foreach(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;as&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*&amp;nbsp;...&amp;nbsp;*/&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

The {{{foreach}}} loop causes an implicit {{{rewind}}} operation on the iterator interface, which in turn causes an implicit load (this {{{OrderSet}}} having not previously loaded), each just-in-time operation cascading all the way up to the connection attempt and so on until throwing the actual exception on lined {{{#0}}} and {{{#1}}} in the printed stack trace; these can be ignored then, and looking at the line {{{#2}}} we can see that the attempted operation was {{{MySQLDataStore-&gt;connect()}}}; those this is also apparent from the text of the exception itself.

The actual exception will be thrown as an object of type {{{TorporException}}}.  This inheritance provides absolutely no new or changed functionality over the standard PHP {{{Exception}}} class except that it allows for {{{catch}}} blocks to be selective.  Catching {{{Exception}}} will get not only {{{Exception}}} but everything that descends from it; catching {{{TorporException}}} instead will catch only that type (and its descendants, of which there are none natively defined), allowing quick differentiation and propagation of errors through multiple catch blocks:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;try&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*&amp;nbsp;...&amp;nbsp;*/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;}&amp;nbsp;catch(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;TorporException&amp;nbsp;$e&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Something&amp;nbsp;anomalous&amp;nbsp;happened&amp;nbsp;in&amp;nbsp;Torpor&amp;nbsp;code&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$e&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getMessage&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&amp;nbsp;catch(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Exception&amp;nbsp;$e&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Something&amp;nbsp;anomalous&amp;nbsp;that&amp;nbsp;almost&amp;nbsp;certainly&amp;nbsp;doesn't&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;originate&amp;nbsp;from&amp;nbsp;Torpor&amp;nbsp;itself&amp;nbsp;or&amp;nbsp;its&amp;nbsp;attempted&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;operations.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$e&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getMessage&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

The inner block will catch anything specifically Torpor related, as indicated in the comments, whereas the exterior block would catch anything it didn't (or which it chose to re-{{{throw}}}).  It can be pretty unwieldy to wrap many common operations in {{{try}}}/{{{catch}}} blocks though, so unless there's a good reason for doing it (knowingly attempting something risky that's likely to fail on a specific operation) it's probably better practice to register a default exception handler which can itself differentiate on which kind of Exception it's been fed; with the additional caveat that after the default handler is invoked by PHP, the program ''will'' exit, so this doesn't fully replicate the functionality of {{{catch}}} which can allow the code to continue beyond the point of error if desired.

Torpor also produces {{{E_USER_WARNING}}} notices whenever it's making an informed but dangerous guess potentially resulting in undesired behavior, such as the truncation of data or precision, issues with character encoding, or some complex relationship management behaviors where an inference has been made as to which of multiple likely scenarios it has defaulted to when multiple ambiguous choices are available.  The code itself has been made {{{E_STRICT}}} compliant across the board, so it's safe to turn on whatever level of logging is desired without a lot of operational noise.

Up: [[Advanced Usage]]
Previous: [[Garbage Collection]]
Next: [[Extension]]</pre>
</div>
<div title="Extension" modifier="Paul Tomlinson" created="200911231507" modified="200911301524" changecount="23">
<pre>Basic Torpor operations are useful for automating [[CRUD]] and navigating object relationships.  This provides a significant boost in development productivity, but those automated factories are fairly bare and don't provide support for business logic or advanced validation.  Fortunately Torpor has ample support for extension of its primitives to provide this kind of enhancement.

First we'll look at 2 examples for extending individual {{{Column}}} classes, followed by a {{{Grid}}} demonstration, with summary notes at the end.
!Boolean Column
The {{{Column}}} class technically has 2 parallel {{{getData}}}/{{{setData}}} avenues: one for use to and from PHP data, the other for data originating from or destined for the repository.  This allows for any arbitrary translation from usage of the data in PHP vs. what's eventually fed into the data store.  Useful examples include date translation, transparent encryption/decryption, or support for PHP primitives not fully supported by the repository.

For example, many databases lack support for a simple boolean column definition, using instead a very small integer or a character enumeration.  Torpor provides support for working with boolean column members natively in PHP, so that every interaction can rely on simple ''true''/''false'' evaluation rather than remembering whether it needs to use ''Y''/''N'', etc.  Assuming a ''Y''/''N'' enumeration, let's implement a {{{CharBool}}} class for mapping ''true''/''false'' states:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;class&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;CharBool&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;extends&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Column&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getPersistData&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$localOnly&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;false&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$return&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$data&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getData&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$localOnly&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(&amp;nbsp;!&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;is_null&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$data&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$return&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$data&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;?&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Y'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;:&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'N'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$return&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;validatePersistData&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$data&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$return&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(&amp;nbsp;!&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;is_null&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$data&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$return&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;strtoupper&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$data&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;==&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Y'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;?&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;true&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;:&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;false&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$return&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

For starters, all extending classes need to literally {{{extend}}} the class they're adding to (in this case, {{{Column}}}).  This allows it to continue working in the Torpor framework without having to re-implement all of the other components of the interface (though if this is desired it's still possible, just not recommended; see the class and interface references in the [[Appendix]]).

We then override 2 {{{public}}} functions:
* ''{{{getPersistData}}}:'' this method is called by the {{{DataStore}}} implementations when feeding data from the class back to the repository.  In order to be compatible with the rest of the framework it must make use of the {{{getData}}} method internally, passing any ''boolean'' argument it receives, which indicates the context of the retrieval (e.g., whether we want the copy of the data inherent to the class or whether to auto-populate and/or follow linkage to other {{{Column}}} objects for the target data).  This keeps all the internal state management in the proper order and context and any associated just-in-time activation that this or other objects may be relying on intact.  Optionally returning {{{null}}} is also important, whether or not the {{{Column}}} itself is considered nullable: if the {{{Column}}} does not have a {{{default}}} value specified in the [[configuration|Config: Columns]], {{{null}}} should be used to indicate a lack of value assignment.  Or for a nullable {{{Column}}}, obviously, the 3rd state is valid even for a traditionally 2-state data type such as this.  The final data returned from this method will be the data fed into the repository; it is the responsibility of the {{{DataStore}}} to provide any data encapsulation or escaping, so don't worry about that here.
* ''{{{validatePersistData}}}:'' this method is used during {{{setData}}} operations when the data comes from repository.  It is responsible for evaluating the single argument provided under the assumption of its originating in the repository, providing any warnings or exceptions, modifying the data as appropriate, and returning the final value for use within PHP.  Nullable data needs to be considered here as well.

With these 2 methods in place, the repository will see any of ''Y''/''N''/''null'' as appropriate, and PHP will get its own ''true''/''false''/''null''.  The last requirement for fitting this into the Torpor deployment is hooking it into the configuration, setting the {{{class}}} attribute of a {{{Column}}} to {{{CharBool}}}, or a {{{DataMap}}} entry for {{{boolean}}} types.  Note that an enumeration or {{{CHAR(1)}}} data type in the repository will be set to a data type of {{{char}}} or {{{varchar}}} in the XML by the [[repository extraction scripts|Repository Extraction]], and will need to be changed to ''boolean'' for this class to really make sense.
!Password Hash Column
In addition to validation and translation to and from the repository it's also possible to provide validation when working with data on the PHP side.  This would apply to any area where simple data type, encoding, and length constraints are not sufficient for maintaining data quality, or where more nuanced controls or implicit translation is desired.

In this example, the {{{validate}}} method is extended to ensure that a business-logic constraint is in place such that the {{{Username}}} and {{{Password}}} members of a {{{User}}} type {{{Grid}}} may not be the same, and also transparently encode the incoming value into an MD5 hash to obscure it for security purposes.

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;class&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;PasswordHash&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;extends&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Column&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;validatePersistData&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$data&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$data&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;validate&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$data&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;strtolower&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$data&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;==&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;strtolower&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getUserName&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;)&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;throwException&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Password&amp;nbsp;cannot&amp;nbsp;be&amp;nbsp;identical&amp;nbsp;to&amp;nbsp;username'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;md5&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$data&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Again, the data management in the {{{validate}}} method is responsible for producing any errors, notices, or exceptions, and returning an appropriately sanitized or otherwise translated value to be stored internally (and accessed via {{{getData}}} mechanisms).  Also as with the prior example, the {{{PasswordHash}}} class needs to be wired up to the {{{type}}} attribute of a {{{Column}}} object in the [[configuration|Configuration]] before it can be used.

Note that {{{validatePersistData}}} is also extended, in this case to provide a blind pass-through on the value it receives.  This is because the native implementation of {{{validatePersistData}}} in the {{{Column}}} class simply uses the method as a facade to the {{{validate}}} method; were this to retain that definition, every time the affected {{{Column}}} object were populated from the database it would become an MD5 hash of the already encoded value, very quickly destroying data integrity.  This patten is used (as opposed to the non-validating example shown here) to ensure data integrity at all touch points, and should not cause issues except for rarely when extending, or even more rarely if the repository and {{{Column}}} definition are ill-suited to one another (or there are horrible data issues).
!User Grid
{{{Grid}}} objects can be extended just as {{{Column}}} objects can.  This can include modification to the base class methods or completely new options and attributes, as shown here:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;class&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;extends&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Grid&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;MD5_REGEX&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'/^[A-Fa-f0-9]{32}$/'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;static&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;passwordMatch&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw1&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw2&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;(&amp;nbsp;!&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;preg_match&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;MD5_REGEX&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;?&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;md5&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;:&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw2&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;(&amp;nbsp;!&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;preg_match&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;MD5_REGEX&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw2&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;?&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;md5&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw2&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;:&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw2&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;==&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw2&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;isUserPassword&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$password&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;passwordMatch&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$password&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getPassword&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;)&amp;nbsp;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Static methods, class constants (highly recommended over string literals directly within the code), and business logic are added as with any other PHP class.  Making use of the implicitly available {{{getPassword}}} method in the {{{isUserPassword}}} example invokes all the same just-in-time loading as it would otherwise, and the provision of static methods allow for the encapsulated business logic to be leveraged generically.  More especially, it keeps all of the logic for what constitutes a password, how it is encoded and compared, to reside within the {{{User}}} class (and by association, possibly the {{{PasswordHash}}} example from above).  Implementing code leveraging these methods need not be concerned with any of those mechanisms directly, which makes modification or migration to other means a well-contained solution in any future revisions.

As with the {{{Column}}} class extension examples, the {{{User}}} class will need to be plugged into an associated {{{Grid}}} definition in the [[XML configuration|Config: Grids]] in order to be automatically instantiated wherever this {{{Grid}}} type is requested.
!Events
The {{{Grid}}} class supports a rich event model, with several methods called automatically at specific times by the corresponding Torpor operation.  Each of these is invoked with no arguments, and no return value is expected.
# ''{{{OnNew}}}:'' Called directly after a new object has been created (and, with the exception of [[TypedGrid]]s, prior the the assignment of any passed arguments).
# ''{{{OnLoad}}}:'' Called immediately following the initial {{{Load}}} of an object, implicit or explicit, regardless of whether the contents originate from an intermediate cache or the repository.
# ''{{{OnBeforePublish}}}:'' Called just //prior// to publishing the contents to the repository, but after any evaluation has been made as to the fitness of the publishing attempt; this should not be used as a method for providing just-in-time values to make publishing viable, since that evaluation has already concluded by the time this is reached (and won't be reached if the evaluation failed).
# ''{{{OnPublish}}}:'' Called immediately following a successful {{{Publish}}}.
# ''{{{OnBeforeDelete}}}:'' Called just //prior// to removing a {{{Grid}}} from the repository.
# ''{{{OnDelete}}}:'' Called immediately following a successful {{{Delete}}}, but after the {{{Grid}}} has been un-loaded and reset to a default state, so identifying data members will not be available.  Technically this could be seen as analogous to {{{OnNew}}}, but each are called discretely in their own circumstances.

Extending these methods allows one to hook into these events with whatever logic or operations they see fit.  A built-in {{{DebugGrid}}} class does exactly this, providing {{{E_USER_NOTICE}}} indications of when each of the events fire without actually modifying any of the operations.
!Epilogue
Extended classes properly configured within the XML will be used whenever the affected {{{Grid}}} or {{{Column}}} object comes into play, no matter the context.  This applies to both {{{Grid}}} and [[TypedGrid]] classes (as does the extension example provided above), providing several implementation options to fit virtually any environment.

While this extension of Torpor primitives is well supported, even extension of the magical {{{get&lt;ObjectTypeName&gt;}}} style methods, they are not easily &quot;reflected&quot; in terms of determining what methods or members exist on a given class.  This is because so much of the functionality is provided via PHP's own magical {{{__get}}}, {{{__set}}}, and {{{__call}}} methods.  There are other means of accessing this kind of information which are covered in the class reference section of the [[Appendix]].

Up: [[Advanced Usage]]
Previous: [[Exceptions]]
Next: [[Sessions]]</pre>
</div>
<div title="Features" modifier="Paul Tomlinson" created="200911010408" modified="200911091425" changecount="22">
<pre>Torpor is categorized by the following features:
!!!Dynamic Factories
There is no code generation step for setting up and using Torpor.  It is necessary to create a [[configuration|Configuration]] file which describes the Grid structure(s) and the underlying repository via XML, but once that's done (and it can be done automatically using the included [[repository extraction scripts|Repository Extraction]]) it is not necessary to generate any PHP code for classes: everything happens from that configuration on-the-fly (though cached after just-in-time analysis as appropriate for performance).
!!!Relational Factories
Any Grid with a defined relationship to any other Grid type can be used to retrieve or create instances of the related Grid.  For example (as laid out in [[simple_sample.xml]] and illustrated in [[Getting Started|Getting Started with Torpor]]), a {{{User}}} Grid is referenced by {{{Order}}}, which implies a one-to-many relationship.  This means that {{{User}}} can be used to retrieve a set ({{{GridSet}}}) of {{{Order}}} instances directly, or to spawn new {{{Order}}} objects as desired.  The reciprocal operates predictably: any {{{Order}}} can be used to retrieve the associated {{{User}}} object from the repository.

Also as illustrated in this example, it's possible to have as many relationships between Grids as there are Columns, including multiple relationships between the same types under different contexts.  Multiple-column keys and relationships are also supported out of the box, as are self referential relationships (as with {{{User}}} to {{{User-as-ReferringUser}}}).
!!!Loose Typing With Attitude
Torpor makes extensive use of the special {{{__call}}}, {{{__get}}}, and {{{__set}}} PHP methods.  These allow for on-the-fly analysis and redirection of the requested methods or variables, which are used in lieu of attempting to create getters and setters for all related objects, columns, etc.  It also means that relaxed (one might say undisciplined) access patterns still benefit from all the rigor and control that went in to making the framework {{{E_ALL|E_STRICT}}} friendly, if not encouraging them outright (though discipline is still urged for the sake of consistency and maintainability; whatever style you're going to use, pick that and stick with it) by making all accessors case-insensitive.  It's also completely indifferent to the placement of underscores, which are commonly used in case-insensitive RDBMS definitions: {{{$x = $object-&gt;getTheColumn();}}} is the same as {{{$x = $object-&gt;getTHE_COLUMN();}}} is the same as {{{$x = $object-&gt;TheColumn;}}} or {{{$x = $object-&gt;THE_COLUMN;}}} (and likewise the reverse for {{{set}}} operations).

Behind this very malleable facade it's still necessary to play nice with the repository, which is almost never as forgiving as PHP (~SQLite is an outlying exception).  String/Byte length, character set encoding, numeric precision, date formats, etc., are all strictly controlled and validated so there should be no surprises down the line.  {{{E_USER_WARNING}}} notices are provided whenever precision is lost or truncation occurs, making debugging unanticipated data management issues from real-world scenarios much easier.
!!!Just In Time
Information is not loaded from the repository until it's needed, keeping objects low in memory consumption and distributing (and in many cases negating) load from a traditional all-up-front pattern to the actual moment of use.  This is married with good repository management as well: the first time an un-loaded Column member of a Grid is accessed, the entire Grid is populated.  Likewise, when retrieving ~GridSet contents, rather than extracting required identifying components (such as primary or unique keys) and then filling in the details piecemeal for each instance after the fact, since it's touching all the same information anyway the whole bundle (however small or large it may be based on pagination constraints) is slurped up and instantiated locally within the application; this relatively small memory trade-off can save countless round-trips to remote resources and dramatically increase application performance while decreasing repository load.

Thus, individual objects which are likely to comprise the majority of an applications operations keep things nimble where they can, and bulk operations more likely to strain the repository or network do their part as well, each in their own way.  The end developer and user experience is seamless.
!!!Caching
Read- and Write- Through caching means that every Grid instance as it moves from or to the repository can optionally be made available in a nearby location for quick retrieval next time it's needed.  By dedicating a limited amount of memory to simple hash-based access it's possible to negate many round trips to the repository.  Not every situation can benefit from caching, but those with a heavy reliance on frequently accessed and infrequently changing data (such as content management, eCommerce, and many web applications) can see significant performance boosts.  This is especially true with distributed caching (such as via the included Memcache adapter), which will allow multiple threads on the same machine or multiple machines in the same cluster to share that hash, providing lateral scalability at the application layer with a much lower increase in demand on the repository which is otherwise a typical bottleneck in N-tier strategies.
!!!Extensibility
Every component of Torpor can be readily extended or modified with very little overhead.  By extending the set of intelligent and adaptable primitives, business logic or other enhancements can be encapsulated in simple deltas to modify or expand the existing functionality as necessary.  Complete replacement is also possible, and in many cases encouraged by the use of basic Interfaces for plug-in components.

Combining that class-based extensibility with flexible configuration means that one Column on one Grid can be enhanced just as easily as all Columns of a given data type (or all Grids) across the entire installation.  New ~DataStore or Cache adapters can readily be fit into the existing architecture.

A complete event model also makes targeted extension extremely simple.  By tying into any of the associated {{{OnNew}}}, {{{OnLoad}}}, {{{OnBeforePublish}}}, {{{OnPublish}}}, {{{OnBeforeDelete}}}, or {{{OnDelete}}} hooks that are all fired at their respective times, a great deal of functionality can be added with surgical precision.
!!!Virtual Entities
While the XML configuration is strictly enforced, it need not be founded in reality.  Grids or Columns best not exposed to the application layer (such as trigger provided last-modified timestamp or identities) can simply be omitted.  Along with their descriptive hints, alias names can be used to smooth out or obscure underlying repository design.  Perhaps more powerfully, any standard [[CRUD]] operations can be overridden with the custom [[Command]] entry, which works with the ~DataStore adapter to enhance or completely replace standard accessors.  Stored Procedures can be used for any, all, or none, and even entire views (and as many update statements as you want) or virtual triggers can be defined directly within Torpor for those instances where the repository cannot or should not (or the DBA's are just picky) be provided.

Previous: [[Introduction]]
Next: [[Getting Started|Getting Started with Torpor]]</pre>
</div>
<div title="Garbage Collection" modifier="Paul Tomlinson" created="200911190043" modified="200911190050" changecount="4">
<pre>The Garbage Collection in PHP uses simple reference counting to determine how many entities still believe an object exists, and removing it once that count drops to zero or once the stack terminates (with &quot;global&quot; and &quot;function&quot; being the only 2 granularities of stack supported).

The problem with this as far as Torpor is concerned is that {{{Column}}} objects know to which {{{Grid}}} instance they belong - so even if the {{{Grid}}} itself goes out of scope and is no longer referenced by anything within the stack itself, at least one reference for every {{{Column}}} object will still exist.  Likewise, the {{{Grid}}} references each of the {{{Column}}} members which belong to it, creating a circular dependency.

For standard web applications this isn't a terribly big deal - once the page execution finishes the stack terminates and everything is cleared.  For longer running routines or persistent applications this can really start to add up though, and looks a lot like a memory leak.

The most common source of rapid memory growth is when objects are instantiated as part of a {{{GridSet}}} or within a loop - especially when those objects are not explicitly freed at the end of the loop.  Assuming that there contiguous {{{Order}}} records (from the standard [[Example|Examples]] series), consider the following code:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;foreach(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;range&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;100&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;as&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$i&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getOrderById&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$i&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*&amp;nbsp;...&amp;nbsp;*/&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Even though the {{{$order}}} variable is overwritten every time, the object to which it previously referred is kept on the stack because internal references persist.  Once {{{$order}}} is reassigned, there is no way to retrieve the prior {{{Order}}} object to which it referred.  That means the above code now has 100 {{{Order}}} objects floating in the ether, each taking up space until the stack to which they belong terminates.  The same is true for an {{{OrderSet}}} style collection:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newOrderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;CriteriaBetween&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;true&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Inclusive&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Load&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;br /&gt;unset(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Oven though {{{$orderSet}}} as a variable has been unassigned, the underlying {{{Order}}} objects will still be hanging around.

There is a workaround for this, but it requires manual intervention.  PHP's magic {{{__destruct}}} method needs to be invoked - since we know that's not going to happen automatically, we can call it manually using a common {{{destroy()}}} method:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;foreach(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;range&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;100&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;as&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$i&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getOrderById&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$i&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*&amp;nbsp;...&amp;nbsp;*/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;destroy&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newOrderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;CriteriaBetween&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;true&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Inclusive&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Load&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;destroy&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;color: #007700&quot;&gt;unset(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderSet&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

The {{{destroy()}}} method walks through the {{{Grid}}} and explicitly removes the {{{Column}}} objects and back-references, allowing them to leave scope and the {{{Grid}}} object to then leave scope as well.  When called on a {{{GridSet}}} it does this to every member {{{Grid}}} object in turn (without causing any implicit loading to take place).  This does not affect the data in the repository or cache, but it ''will'' affect any variables that still reference an object that has been {{{destroy}}ed; these will cause the persisting variable to produce errors very quickly when attempts are made to access non-existent members.  It is therefor recommended that this be used with extreme caution and care to ensure no toes are stepped on.

Up: [[Advanced Usage]]
Next: [[Exceptions]]</pre>
</div>
<div title="Getting Started with Torpor" modifier="Paul Tomlinson" created="200910312317" modified="200911301546" changecount="41">
<pre>!!Installation
After [[downloading a distribution package|Downloads]] the relevant PHP files will be extracted to a folder like {{{torpor/src}}}.

These source files should be placed so as to be accessible to the PHP include path (or the path modified to incorporate the installation directory). The main {{{Torpor.php}}} file will affect an inclusion of necessary supporting files based on its current directory.

It is recommended to run the provided {{{torpor/src/test/test.php}}} in your target environment to confirm successful installation, dependencies, and operation. Be advised that command line and web server invocations frequently differ in the available environments and settings and may produce different or unexpected results such as failure to include proper files and locate dependent packages. The successful execution should be confirmed in the same conditions you expect to use the package. 
!![[Configuration]]
All configuration is performed via XML, including optional settings, data engine access, and descriptions of the data objects themselves. This XML must be prepared according to the specifications outlined in the more exhaustive [[Configuration]] section of this documentation and will be validated against the included {{{TorporConfig.xsd}}} schema file prior to loading. It is recommended to test this validation manually during development in order to ensure successful loading (which will separate syntax errors from logic errors, making debugging easier). The included {{{torpor/tools/validate}}} script is provided for this purpose.

Torpor will look in the PHP include path for the file {{{TorporConfig.xml}}} by default, unless something else is passed as an argument to the {{{Torpor::initialize()}}} method (or the {{{TORPOR_CONFIG}}} environment variable is set, which may contain either a filename, URI, or even XML content).  This can be passed either as a string containing the XML, a file pointer, file name, ~SimpleXML instance, or URI. For the best performance it is recommended to use file based access rather than reading from ~URIs over the network.  The easiest way to establish the configuration file is by using one of the [[data repository extraction scripts|Repository Extraction]] (available under {{{torpor/tools}}}), which will to the best of its abilities describe the layout of your repository in compatible XML - each comes with its own instructions regarding parameters for invocation.  More details can be found under the [[Configuration]] section.
!!Invocation
Torpor can be used in either instance or singleton modes (although making use of the TypedGrid classes __requires__ singleton operation), and initialization is similar in either case:
!!!Instance
&lt;html&gt;
&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$torpor&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;initialize&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'TorporConfig.xml'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;
&lt;/html&gt;
!!!Singleton
&lt;html&gt;
&lt;span style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;Torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getInstance&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;initialize&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'TorporConfig.xml'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;
&lt;/html&gt;

From there it's a matter of setting up your first object through the {{{Torpor}}} factory.  Assuming the configuration file is [[simple_sample.xml]] and Torpor is being used without the aid of TypedGrid classes (note that after something like {{{$MyTorpor = new Torpor();}}} and {{{$MyTorpor = Torpor::getInstance();}}} everything is the same; in this usage pattern singleton just guarantees initialization only happens once, and uses less memory for repeat instance acquisitions):

&lt;html&gt;
&lt;div style=&quot;font-family: monospace;&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getInstance&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;initialize&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'simple_sample.xml'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;get&amp;lt;Object&amp;gt;ById:&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getUserById&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;12345&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;******************************&lt;br /&gt;//&amp;nbsp;**&amp;nbsp;&amp;nbsp;Related&amp;nbsp;Object&amp;nbsp;Factory&amp;nbsp;&amp;nbsp;**&lt;br /&gt;//&amp;nbsp;******************************&lt;br /&gt;//&amp;nbsp;get&amp;lt;Object&amp;gt;Set&amp;nbsp;(implicit&amp;nbsp;&quot;...From&amp;lt;Object&amp;gt;&quot;):&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderHistory&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getOrderSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;foreach(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$orderHistory&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;as&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*&amp;nbsp;...&amp;nbsp;*/&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;new&amp;lt;Object&amp;gt;&amp;nbsp;(implicit&amp;nbsp;&quot;...From&amp;lt;Object&amp;gt;&quot;):&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newOrder&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;***********************************&lt;br /&gt;//&amp;nbsp;**&amp;nbsp;&amp;nbsp;Alternate&amp;nbsp;Access&amp;nbsp;Mechanisms&amp;nbsp;&amp;nbsp;**&lt;br /&gt;//&amp;nbsp;***********************************&lt;br /&gt;//&amp;nbsp;Automatic&amp;nbsp;relationship&amp;nbsp;column&amp;nbsp;traversal&amp;nbsp;and&amp;nbsp;set&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setSeller&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getUserById&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;67890&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Identical&amp;nbsp;to:&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setSellerId&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;67890&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;The&amp;nbsp;following&amp;nbsp;are&amp;nbsp;equivalent:&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setPurchaseDate&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Y-m-d&amp;nbsp;H:i:s'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;PurchaseDate&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Y-m-d&amp;nbsp;H:i:s'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;PURCHASE_DATE&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Y-m-d&amp;nbsp;H:i:s'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;**********************************&lt;br /&gt;//&amp;nbsp;**&amp;nbsp;&amp;nbsp;Late&amp;nbsp;binding&amp;nbsp;relationships&amp;nbsp;&amp;nbsp;**&lt;br /&gt;//&amp;nbsp;**********************************&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$secondUser&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$secondUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setReferringUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;$secondUser&amp;nbsp;does&amp;nbsp;not&amp;nbsp;yet&amp;nbsp;exist&amp;nbsp;in&amp;nbsp;the&amp;nbsp;repository,&lt;br /&gt;//&amp;nbsp;so&amp;nbsp;this&amp;nbsp;sets&amp;nbsp;up&amp;nbsp;an&amp;nbsp;implicit&amp;nbsp;association&amp;nbsp;that&lt;br /&gt;//&amp;nbsp;will&amp;nbsp;retrieve&amp;nbsp;the&amp;nbsp;relational&amp;nbsp;column&amp;nbsp;values&amp;nbsp;when&lt;br /&gt;//&amp;nbsp;they&amp;nbsp;become&amp;nbsp;available.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$secondUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newOrder&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setSeller&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setDate&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Y-m-d&amp;nbsp;H:i:s'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Neither&amp;nbsp;ShippingAddress&amp;nbsp;nor&amp;nbsp;ShippingType&amp;nbsp;are&amp;nbsp;set&lt;br /&gt;//&amp;nbsp;up&amp;nbsp;in&amp;nbsp;this&amp;nbsp;example,&amp;nbsp;but&amp;nbsp;you&amp;nbsp;get&amp;nbsp;the&amp;nbsp;idea.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setShippingAddressId&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;15243&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setShippingTypeId&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;34251&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;This&amp;nbsp;causes&amp;nbsp;$secondUser&amp;nbsp;to&amp;nbsp;publish&amp;nbsp;in&amp;nbsp;order&amp;nbsp;to&lt;br /&gt;//&amp;nbsp;acquire&amp;nbsp;a&amp;nbsp;primary&amp;nbsp;key&amp;nbsp;because&amp;nbsp;generatedOnPublish&lt;br /&gt;//&amp;nbsp;is&amp;nbsp;set&amp;nbsp;to&amp;nbsp;true&amp;nbsp;(meaning&amp;nbsp;we&amp;nbsp;can&amp;nbsp;get&amp;nbsp;this&amp;nbsp;from&amp;nbsp;the&lt;br /&gt;//&amp;nbsp;repository)&amp;nbsp;for&amp;nbsp;the&amp;nbsp;related&amp;nbsp;Column,&amp;nbsp;and&amp;nbsp;because&lt;br /&gt;//&amp;nbsp;the&amp;nbsp;default&amp;nbsp;Torpor&amp;nbsp;configuration&amp;nbsp;setting&amp;nbsp;of&lt;br /&gt;//&amp;nbsp;PublishDependencies&amp;nbsp;is&amp;nbsp;also&amp;nbsp;true.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$order&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Publish&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Publishes&amp;nbsp;$secondUser&amp;nbsp;first.
&lt;/div&gt;
&lt;/html&gt;

[[TypedGrids|TypedGrid]] omit the need to make use of a {{{$torpor}}} instance directly, replacing the {{{new}}} and {{{...ById}}} commands with standard PHP constructor operations:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Identical&amp;nbsp;to&amp;nbsp;-&amp;gt;getUserById(&amp;nbsp;12345&amp;nbsp;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;12345&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Identical&amp;nbsp;to&amp;nbsp;-&amp;gt;newUser()&amp;nbsp;or&amp;nbsp;-&amp;gt;newUserSet();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;UserSet&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

This is a fairly dense first example, but it should be noted that (assuming the {{{test}}} database specified exists according to the [[simple_sample.xml]] definition) this is all it takes to use Torpor: there is no code generation or series of includes or manual overhead; the factory pattern goes right to work dynamically typing instances of [[Grid]] objects to match the definitions and relating them to one another.

Previous: [[Features]]
Next: [[Configuration]] (or [[Examples]] if you're impatient)</pre>
</div>
<div title="Introduction" modifier="Paul Tomlinson" created="200910311914" modified="200911011713" changecount="11">
<pre>Torpor is a persistence layer abstraction in PHP, providing a form of object-relational mapping derived from the design of the database (and encouraging good design principles). It is written entirely in PHP, and has been designed with ease of implementation and performance as primary goals. 
!!Objective
Torpor was created to perform all the legwork between the design of a database and the most common patterns of access and manipulation to it. This comes from several years of working with database abstractions in numerous languages and scopes of implementation, from simple one-off scripts up through major infrastructure for insurance, web hosting, and ecommerce retailers. In almost all cases, regardless of the tools in play, the ways in which data is accessed, combined, and published, follow very predictable patterns. There are [[dozens of projects|Alternatives]] in their respective languages which seek to encapsulate those patterns into common abstractions, each enforcing their own pragmatism on the implementation.

Torpor seeks to be lightweight and sufficiently logical that it plays well with developer needs, and is extensible and configurable enough that even if the defaults aren't perfectly suited it can still be adapted to stay out of the way (see [[Alternatives]] for a list of other comparable PHP ORM solutions you may want to consider as well).  It aims to be the shortest possible distance between idea and implementation without compromising on enterprise level features normally available only with considerable effort and expenditure of resources. These [[features|Features]] include automatic design and instantiation for data objects, implicit factories for related entities, updatable collections, data engine agnosticism, and performance options for just-in-time fetches, bulk loading, and distributed caching.  It should be the easiest way to work with native data and objects in PHP, and likewise on the reciprocal data storage interface.

In order to be useful to the PHP community this needed to be as simple to the end user as possible and compatible with established conventions rather than requiring entirely new or radically different theories or adaptations to be used. It should feel, if we have done our job right, like the best possible object interface that you would come up with were it all to be written manually and with painstaking care. Our focus on quality, best practices, and effective performance have been uncompromising, and [[feedback|Feedback]] for improvement is always welcome.
!!Concepts
Torpor works with data in tabular formats, but does not refer to them specifically as Tables in order to avoid confusion with database specific terminology, since the data repository may not actually be a database (in much the same way that ORM frameworks typically refer to the &quot;persistence layer&quot; to be generic). Instead, the term Grid is used.  This refers to the general definition of the Grid layout itself by representing a generic record structure from the same: the Grid is composed of the Columns common to every line item - in this way it refers to both the ovarching Grid design as a tabular entity and an instance record from the same.  Hopefully this isn't too confusing - it's mostly for convenience since there are no other components which describe the collected structure, and in practice should be fairly straightforward.

Heavy reliance is made on factory patterns, using one object as the gateway to the creation (or retrieval) of other related objects. It is possible to use the system more generically without relying on this behind the scenes magic, but there are some key benefits which make it worthwhile to adhere to (especially late-binding data relationships, keeping multiple object references in sync prior to publishing to the data store). 
!!Requirements
Torpor is written entirely in PHP and requires version 5.1.0 or greater, with the ~SimpleXML and DOM extensions, and support for the data engine of your choice. This target version was chosen in order to get the best overlap between capabilities and availability - some of the nicer conventions and features of later versions (such as name spaces and some dynamic execution mechanisms such as {{{__callStatic}}}) have been omitted in order to maintain this compatibility. As a result, all classes are declared in the global namespace and it is up to the end user to ensure collisions do not occur.
!!License
Torpor is offered under the [[MIT license|http://en.wikipedia.org/wiki/MIT_License]], which allows for inclusion in paid projects and unrestricted extension of the code so long as others are afforded the same rights. We would ask that any useful modification be propagated back to the project, and will even say &quot;pretty please&quot; - but you're otherwise completely unrestricted in the use and distribution of this software. 

Next: [[Features]]</pre>
</div>
<div title="MainMenu" modifier="Paul Tomlinson" created="200910311907" modified="200911030705" changecount="8">
<pre>[[Introduction]]
[[Features]]
[[Getting Started|Getting Started with Torpor]]
[[Configuration]]
[[Examples]]
[[Advanced Usage]]
[[Appendix]]</pre>
</div>
<div title="MarkupPostBody" modifier="Paul Tomlinson" created="200911010514" changecount="1">
<pre></pre>
</div>
<div title="PageTemplate" modifier="Paul Tomlinson" created="200911010500" modified="200911051408" changecount="9">
<pre>&lt;!--{{{--&gt;
&lt;div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryDark]]'&gt;
&lt;div class='headerShadow'&gt;
&lt;span class='siteTitle' refresh='content' tiddler='SiteTitle'&gt;&lt;/span&gt;&amp;nbsp;
&lt;span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div class='headerForeground'&gt;
&lt;span class='siteTitle' refresh='content' tiddler='SiteTitle'&gt;&lt;/span&gt;&amp;nbsp;
&lt;span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id='mainMenu' refresh='content' tiddler='MainMenu'&gt;&lt;/div&gt;
&lt;div id='sidebar'&gt;
&lt;div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'&gt;&lt;/div&gt;
&lt;div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div id='displayArea'&gt;
&lt;div id='messageArea'&gt;&lt;/div&gt;
&lt;div id='tiddlerDisplay'&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class='footer' style='margin: 2em; clear: all; width: 50%; margin: 0px auto;'&gt;
All content provided under the &lt;a href=&quot;http://www.opensource.org/licenses/mit-license.php&quot;&gt;MIT License&lt;/a&gt;, without warranty or other restriction.  Use at your own risk, as you see fit, and allow others to do the same. // Visit us at the &lt;a ref=&quot;http://code.google.com/p/torpor-php&quot;&gt;Torpor home page&lt;/a&gt;.
&lt;/div&gt;
&lt;!--}}}--&gt;</pre>
</div>
<div title="Paul Tomlinson" modifier="Paul Tomlinson" created="200911010504" modified="200911010505" changecount="4">
<pre>Email: [[paul@paultomlinson.net|mailto:paul@paultomlinson.net]]
Home page: [[paultomlinson.net|http://paultomlinson.net]]</pre>
</div>
<div title="Revision" modifier="Paul Tomlinson" created="200911010525" changecount="1">
<pre>$Rev: 73 $</pre>
</div>
<div title="Sessions" modifier="Paul Tomlinson" created="200911271717" modified="200911271808" changecount="7">
<pre>Use of [[caching|Config: Cache]] is highly recommended, keeping referenced data close to the point of utilization to shorten subsequent lookups after an initial load.  PHP Sessions are a very convenient way of doing that for one thread at a time, and while this is not as useful (or safe) as doing a distributed cache it's still better than nothing.

PHP Sessions allow for the caching of complex objects, provided that the definition of the object can be located before it is deserialized back onto the stack.  However, Torpor objects are highly contextual and thus potentially very large: a {{{Grid}}} object refers not only to its {{{Column}}} data members, but also the {{{Torpor}}} instance (singleton or otherwise) which is its connection to the repository.  The {{{Torpor}}} instance in turn maintains references to its parsed configuration, repository connections, cache instances, etc.; thus attempting to store a {{{Grid}}} in the session a difficult proposition where referential and connective integrity are messy if not impossible and therefor not recommended.

There are a few options to help overcome these limitations.  The first is the use of one of the provided caching mechanisms, which save only the relevant details from a loaded (and that &quot;loaded&quot; part is essential) {{{Grid}}} instance.  This has a slight limitation however in that it only acts as an intermediate cache from the {{{DataStore}}} adapter and the repository, and will only return the data when it's requested by an exact key - which means the key must still be stored locally.  This isn't ''too'' unwieldy, but does require an extra step:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;Torpor&amp;nbsp;Instance&amp;nbsp;Access&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$current_user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getUserById&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$_SESSION&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'current_user.id'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;]&amp;nbsp;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;TypedCrid&amp;nbsp;access&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$current_user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$_SESSION&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'current_user.id'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;]&amp;nbsp;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Again, this only applies to loaded {{{Grid}}} instances which can retrieve that object from Torpor's cache.

For working with partial {{{Grid}}} data (user-populated or not fully loaded) or otherwise serializing the content of a {{{Grid}}}, there are a few built-in methods that may prove useful:
* ''{{{Grid::dumpArray}}}:'' returns an associative array with Torpor style key names for each {{{Column}}} and the data of the corresponding {{{Column}}} member.  This will implicitly load the {{{Grid}}} if it can be and has not already been.
* ''{{{Grid::dumpObject}}}:'' same as {{{dumpArray}}}, but returns the contents as a PHP {{{stdClass}}} object instead.
* ''{{{Grid::LoadFromArray}}}:'' takes an associative array argument and populates all of the {{{Column}}} members of the {{{Grid}}} with corresponding data.  A second optional ''boolean'' argument will determine whether or not the {{{Grid}}} is marked as having been loaded as well; however, if there is //not// a corresponding repository record this should not be set to ''true'' (defaults to ''false'').
* ''{{{Grid::LoadFromObject}}}:'' sames as {{{LoadFromArray}}}, but takes a PHP {{{stdClass}}} object as the first argument instead of an associative array.

A word of caution: all standard constraints and conventions apply to loading data via this mechanisms as doing regular data assignment.  That is, a {{{NULL}}} data value passed to a {{{Column}}} that is marked as non-nullable //will// throw an exception.  This is an especial problem in this area because a {{{Grid}}} that has not loaded will have {{{NULL}}} data members unless those members have a ''default'' value specified in the configuration.  This means it's possible to pass from {{{Grid::dumpArray}}} straight into {{{Grid::LoadFromArray}}} and counter-intuitively produce an exception.  The best workaround for this, other then ensuring that all {{{Grid}}} objects are loaded, is to leverage the optional arguments on the {{{dump&lt;...&gt;}}} methods:
# {{{boolean }}}//{{{$all}}}//: defaults to ''true'', returns all {{{Column}}} members even if they do no {{{hasData}}}.  If set to ''false'', only those {{{Column}}} objects which have been explicitly populated will be returned.
# {{{boolean }}}//{{{$load}}}//: defaults to ''true'', determines whether or not an implicit {{{Load}}} attempt will be made (assuming {{{Grid::canLoad()}}}) prior to returning results.  If set to ''false'' only the current contents will be returned.

For more details see the {{{Grid}}} [[class reference|Class: Grid]].

If any of these options will be used with any frequency it's recommended to create some intelligent wrappers or possibly even override the default session handler to be able to handle {{{Grid}}} instances intelligently.

Up: [[Advanced Usage]]
Previous: [[Extension]]
Next: [[Typed Grids|TypedGrid]]</pre>
</div>
<div title="SiteSubtitle" modifier="Paul" created="200910311904" changecount="1">
<pre>release 1.0 Documentation and Usage Guide</pre>
</div>
<div title="SiteTitle" modifier="Paul" created="200910311901" changecount="1">
<pre>Torpor</pre>
</div>
<div title="StyleSheet" modifier="Paul Tomlinson" created="200911010521" modified="200911011526" changecount="5">
<pre>.tiddler { border: 1px solid [[ColorPalette::TertiaryLight]]; margin-bottom: 1em; padding-bottom: 0.5em; }
.footer { color: [[ColorPalette::TertiaryMid]]; text-align: center; }</pre>
</div>
<div title="Supported Persistence Engines" modifier="Paul Tomlinson" created="200911030615" modified="200911051615" changecount="14">
<pre>| !Repository Type | !Repository Version | !Torpor Name* | !Torpor Version | !Torpor Class(.php) |h
| ~MySQL | 5.0+ | ~MySQL | 1.0 | [[MySQLDataStore|Class: MySQLDataStore]] |
|~|~| ~MySQLi | //future// | -- |
| Postgres | -- | Postgres | 1.0.x (&gt; 1.0) | -- |
| ODBC | -- | ODBC | //future// | -- |
| Oracle | 10g+ | Oracle&lt;br/&gt;OCI | 1.0 | [[OracleDataStore|Class: OracleDataStore]] |
| ~SQLite | 3 | ~SQLite | 1.0 | [[SQLiteDataStore|Class: SQLiteDataStore]] |
| SQL Server | 2005+ | ~SQLServer&lt;br/&gt;MSSQL | 1.0 | [[MSSQLDataStore|Class: MSSQLDataStore]] |
 *Names are case-insensitive in XML settings.</pre>
</div>
<div title="TypedGrid" modifier="Paul Tomlinson" created="200911281654" modified="200911301559" changecount="24">
<pre>Use of the {{{TypedGridClasses}}} [[option|Config: Options]] creates once class for every {{{Grid}}} defined in the configuration, as an extension of the built-in {{{TypedGrid}}} class (the resulting class name may optionally have a prefix as specified by the {{{TypedGridClassesPrefix}}} option), which itself is an extension to the {{{Grid}}} class and therefore supports all the same members, interfaces, and features.  This dynamic class creation allows for &quot;typing&quot; or type-hinting of each of the {{{Grid}}} instances to a more specific class qualifier than &quot;Grid,&quot; as well as for factory-independent instantiation in singleton mode (technically it's also possible to use this pattern in instance mode, but only by passing a {{{Torpor}}} instance as an argument to every new object's constructor which can become unmaintainable rather quickly).

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;instead&amp;nbsp;of...&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$MyTorpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;newUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

Which also allows for class verification and hints:
&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;if(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$obj&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;instanceof&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*&amp;nbsp;...&amp;nbsp;*/&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;}&lt;br /&gt;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;handleUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&amp;nbsp;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;/*&amp;nbsp;...&amp;nbsp;*/&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;
...etc.

The real genius of all of this is that these classes (and corresponding {{{TypedGridSet}}} classes) are created on-the-fly by Torpor as required.  There are a few exercises required to initially set up this functionality, after which modification and extension are extremely straightforward.

Using this option there is no need to set the {{{class}}} attribute of each {{{Grid}}} in the configuration; a correspondingly named class is automatic.  Use of {{{TypedGrid}}s and other extensions to {{{Grid}}} at the same time is not recommended or supported, and may produce unexpected errors.
!Autoload
The first requirement is to turn on {{{TypedGridClasses}}} in the [[configuration|Config: Options]] by setting the value to ''true''.  The {{{TypedGridClassesPrefix}}} may optionally be used to provide a character prefix which will be added to each of the class names (e.g., a {{{TypedGridClassesPrefix}}} of &quot;{{{Torpor}}}&quot; and a {{{Grid}}} with a {{{name}}}/{{{dataname}}} value of &quot;{{{User}}}&quot; would result in a class of &quot;{{{TorporUser}}}&quot;).  The second requirement is to place the automatic validation/class creation routine into the PHP magic {{{__autoload}}} function (see the [[PHP documentation|http://php.net/manual/en/language.oop5.autoload.php]] for in-depth information).  It is recommended to place Torpor's call as the very last of the process in order to allow for easier extension, which will be explored below.  An example of this would be:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;__autoload&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$className&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$classesDirectories&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;explode&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;PATH_SEPARATOR&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;get_include_path&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$classesDirectories&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;[]&amp;nbsp;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'/some/custom/library/path'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$found&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;foreach(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$classesDirectories&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;as&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$classesDirectory&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pathToClassFile&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$classesDirectory&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'/'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$className&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'.php'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;file_exists&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pathToClassFile&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;require_once(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pathToClassFile&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$found&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(&amp;nbsp;!&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$found&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$torpor&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getInstance&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(&amp;nbsp;!&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;isInitialized&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;initialize&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'MyCustomConfig.xml'&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$torpor&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;typedGridClassCheck&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$className&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

This example assumes that any requested class name not already defined will either have a file corresponding to the class name (special consideration must be taken on case-sensitive file systems) with a '.php' extension either in the include path or in a custom library path, or will be defined by Torpor via the {{{typedGridClassCheck}}} method on a singleton instance.  If the configuration file is named {{{TorporConfig.xml}}} and exists in PHP include path, the only required line would be {{{Torpor::typedGridClassCheck( $className );}}}, which would implicitly acquire the singleton, conditionally initialize it, and then perform the class check.

The {{{typedGridClassCheck}}} method looks at the configuration, determines whether or not the requested class name matches any of the defined {{{Grid}}} entities (including any prefix), and if not, defines the class as extending {{{TypedGrid}}} with no other options or customizations.  The same process is used for {{{TypedGridSet}}} instances, which are accessed by appending {{{Set}}} to the class name.

Using this process, no class exists until it is first requested, either by direct instantiation or through factory methods on another class or set.
!Instantiation
Each {{{TypedGrid}}} accepts 2 kinds of arguments to the constructor, both optional.
# A {{{Torpor}}} instance to use instead of the implicit singleton acquisition.
# One or more values to automatically assign as members of the [[primary key|Config: Keys: Primary]] after the instance has been created.  For multiple-column keys these arguments should be passed in the order that the key is defined in the configuration.  Assuming they key population is complete and corresponds with known records in the repository, the object will then be capable of loading as if it had been created via {{{Torpor::get&lt;Object&gt;ById()}}}.

Instances can be created through use of the {{{new}}} keyword just as with other PHP objects, or through all of the same factory methods and relationships already explored in the [[related objects|Examples: Related Objects]] examples.

Note: as with other related objects, the use of any prefix (via the {{{TypedGridClassesPrefix}}} configuration option) does not alter the invocation of related object syntax.  A {{{Grid}}} with a {{{name}}}/{{{dataname}}} of {{{User}}}, even if given a {{{My}}} prefix to result in {{{MyUser}}}, will still require use of {{{$order-&gt;getUser()}}} syntax rather than {{{$order-&gt;getMyUser()}}}.

!Extension
The evaluated PHP code used by Torpor for creating each named {{{Grid}}} class is extremely simple:
&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;class&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;extends&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;TypedGrid&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

The guts of the {{{TypedGrid}}} class being extended are responsible for using the class name in conjunction with the {{{Torpor}}} instance to determine what type of {{{Grid}}} it is during construction, and sets up all of its internals and data members during that time by working with that instance.

It is possible and highly recommended for an implementing developer to use this same extension, and even the same class names, in order to specify customizations.  Re-writing the {{{User}}} class [[extension|Extension]] example for use with {{{TypedGrid}}}s simply requires changing the word {{{Grid}}} to {{{TypedGrid}}} in the name definition:

&lt;html&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;color: #007700&quot;&gt;class&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;extends&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;TypedGrid&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;MD5_REGEX&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'/^[A-Fa-f0-9]{32}$/'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;static&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;passwordMatch&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw1&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw2&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;(&amp;nbsp;!&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;preg_match&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;MD5_REGEX&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;?&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;md5&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;:&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw2&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;(&amp;nbsp;!&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;preg_match&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;MD5_REGEX&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw2&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;?&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;md5&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw2&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;:&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw2&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;==&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$pw2&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;isUserPassword&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$password&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;passwordMatch&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$password&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getPassword&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;)&amp;nbsp;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/html&gt;

So long as this code is evaluated before the {{{typedGridClassCheck}}} method is invoked, this definition will stand and be used in all the same ways and places.  Same goes for extensions to {{{TypedGridSet}}}.

The constructor should not be overridden unless the call is still included in the new constructor method via a {{{parent::__construct()}}} call, propagating any arguments as appropriate.  However, the {{{OnNew()}}} method will also be invoked at the end of construction and assignment of any initial value assignment (those arguments passed to the constructor), making that a recommended avenue for managing instantiation and initialization.

One final caveat for manual extension of the {{{TypedGrid}}} class: the object automatically associates with the singleton {{{Torpor}}} instance unless one is provided to the constructor, as previously discussed.  In the {{{__autoload}}} example above, the singleton is initialized using a custom configuration (something other than &quot;~TorporConfig.xml&quot; available in the PHP include path) when a {{{TypedGrid}}} object is being created.  However, if that class definition has been provided via other means, either the {{{typedGridClassCheck}}} method will be bypassed, along with the initialization block (which is easy enough to compensate for by moving the initialization earlier in the {{{__autoload}}} function), or the entirety of {{{__autoload}}} will be bypassed because the class definition is already a part of the operating environment.

If this happens it's possible that the class will attempt to derive its {{{Grid}}} affiliation and data members from an uninitialized {{{Torpor}}} instance, failing noisily.  As a workaround it is recommended to either absolutely ensure that the singleton has already been initialized through a common means guaranteed to execute beforehand, or by setting the {{{TORPOR_CONFIG}}} environment variable to indicate the location (via file or URI) of the desired configuration which will override the default &quot;~TorporConfig.xml&quot; - or you can just name your configuration file according to the default and all is well that way too.

Up: [[Advanced Usage]]
Previous: [[Sessions]]
Next: [[Appendix]]</pre>
</div>
<div title="simple_sample.xml" modifier="Paul Tomlinson" created="200911010320" modified="200911010332" changecount="2">
<pre>&lt;html&gt;
&lt;div style=&quot;background-color: #FFF; font-family: monospace; whitespace:nowrap;&quot;&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;?&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;xml&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;version&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;'1.0'&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;?&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#CC20CC&quot;&gt;trpr&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;TorporConfig&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;version&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;0.1&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;xmlns&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;trpr&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;&lt;a href=&quot;http://www.tricornersoftware.com/Products/Torpor/Config/0.1&quot;&gt;http://www.tricornersoftware.com/Products/Torpor/Config/0.1&lt;/a&gt;&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Repository&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;DataStore&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;MySQL&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Parameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;username&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;value&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;test&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Parameter&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;database&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;value&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;test&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/DataStore&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Repository&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Grids&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Grid&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;User&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;USERS&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;class&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;User&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Columns&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Id&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;USER_ID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;generatedOnPublish&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;true&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;unsigned&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ReferringUserId&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;REFERRING_USER_ID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;unsigned&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;UserName&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;USER_NAME&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;varchar&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;length&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;255&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Email&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;EMAIL_ADDRESS&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;varchar&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;length&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;255&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;PasswordHash&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;PASSWORD&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;varchar&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;class&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;PasswordHash&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;length&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;32&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Columns&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Keys&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Foreign&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ReferringUserId&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceGrid&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;User&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceGridAlias&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ReferringUser&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceColumn&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Id&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Foreign&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Primary&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Id&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Primary&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Unique&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;UserName&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Unique&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Unique&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Email&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Unique&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Keys&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Grid&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Grid&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Order&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ORDERS&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Columns&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Id&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ORDER_ID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;generatedOnPublish&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;true&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;unsigned&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;UserId&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;USER_ID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;unsigned&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;SellerId&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;SELLER_ID&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;unsigned&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Date&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ORDER_DATE&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;datetime&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ShippingAddressId&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;SHIPPING_ADDRESS&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;unsigned&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Column&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;name&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;ShippingTypeId&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;dataName&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;SHIPPING_TYPE&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;type&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;unsigned&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Columns&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Keys&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Foreign&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;UserId&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceGrid&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;User&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceColumn&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Id&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;SellerId&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceGrid&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;User&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceGridAlias&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Seller&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;referenceColumn&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Id&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Foreign&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Primary&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Id&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Primary&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Unique&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;UserId&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;Key&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#009900&quot;&gt;column&lt;/font&gt;=&lt;font color=&quot;#990000&quot;&gt;&amp;quot;Date&amp;quot;&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;/&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Unique&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Keys&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Grid&amp;gt;&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/Grids&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color=&quot;#5555CC&quot;&gt;&amp;lt;/&lt;/font&gt;&lt;font color=&quot;#CC20CC&quot;&gt;trpr&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#5555CC&quot;&gt;TorporConfig&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;/div&gt;
&lt;/html&gt;</pre>
</div>
</div>
<!--POST-STOREAREA-->
<!--POST-BODY-START-->
<!--POST-BODY-END-->
<script id="jsArea" type="text/javascript">
//<![CDATA[
//
// Please note:
//
// * This code is designed to be readable but for compactness it only includes brief comments. You can see fuller comments
//   in the project Subversion repository at http://svn.tiddlywiki.org/Trunk/core/
//
// * You should never need to modify this source code directly. TiddlyWiki is carefully designed to allow deep customisation
//   without changing the core code. Please consult the development group at http://groups.google.com/group/TiddlyWikiDev
//

//--
//-- Configuration repository
//--

// Miscellaneous options
var config = {
	numRssItems: 20, // Number of items in the RSS feed
	animDuration: 400, // Duration of UI animations in milliseconds
	cascadeFast: 20, // Speed for cascade animations (higher == slower)
	cascadeSlow: 60, // Speed for EasterEgg cascade animations
	cascadeDepth: 5, // Depth of cascade animation
	locale: "en" // W3C language tag
};

// Hashmap of alternative parsers for the wikifier
config.parsers = {};

// Adaptors
config.adaptors = {};
config.defaultAdaptor = null;

// Backstage tasks
config.tasks = {};

// Annotations
config.annotations = {};

// Custom fields to be automatically added to new tiddlers
config.defaultCustomFields = {};

// Messages
config.messages = {
	messageClose: {},
	dates: {},
	tiddlerPopup: {}
};

// Options that can be set in the options panel and/or cookies
config.options = {
	chkRegExpSearch: false,
	chkCaseSensitiveSearch: false,
	chkIncrementalSearch: true,
	chkAnimate: true,
	chkSaveBackups: true,
	chkAutoSave: false,
	chkGenerateAnRssFeed: false,
	chkSaveEmptyTemplate: false,
	chkOpenInNewWindow: true,
	chkToggleLinks: false,
	chkHttpReadOnly: true,
	chkForceMinorUpdate: false,
	chkConfirmDelete: true,
	chkInsertTabs: false,
	chkUsePreForStorage: true, // Whether to use <pre> format for storage
	chkDisplayInstrumentation: false,
	txtBackupFolder: "",
	txtEditorFocus: "text",
	txtMainTab: "tabTimeline",
	txtMoreTab: "moreTabAll",
	txtMaxEditRows: "30",
	txtFileSystemCharSet: "UTF-8",
	txtTheme: ""
	};
config.optionsDesc = {};

// Default tiddler templates
var DEFAULT_VIEW_TEMPLATE = 1;
var DEFAULT_EDIT_TEMPLATE = 2;
config.tiddlerTemplates = {
	1: "ViewTemplate",
	2: "EditTemplate"
};

// More messages (rather a legacy layout that should not really be like this)
config.views = {
	wikified: {
		tag: {}
	},
	editor: {
		tagChooser: {}
	}
};

// Backstage tasks
config.backstageTasks = ["save","sync","importTask","tweak","upgrade","plugins"];

// Extensions
config.extensions = {};

// Macros; each has a 'handler' member that is inserted later
config.macros = {
	today: {},
	version: {},
	search: {sizeTextbox: 15},
	tiddler: {},
	tag: {},
	tags: {},
	tagging: {},
	timeline: {},
	allTags: {},
	list: {
		all: {},
		missing: {},
		orphans: {},
		shadowed: {},
		touched: {},
		filter: {}
	},
	closeAll: {},
	permaview: {},
	saveChanges: {},
	slider: {},
	option: {},
	options: {},
	newTiddler: {},
	newJournal: {},
	tabs: {},
	gradient: {},
	message: {},
	view: {defaultView: "text"},
	edit: {},
	tagChooser: {},
	toolbar: {},
	plugins: {},
	refreshDisplay: {},
	importTiddlers: {},
	upgrade: {
		source: "http://www.tiddlywiki.com/upgrade/",
		backupExtension: "pre.core.upgrade"
	},
	sync: {},
	annotations: {}
};

// Commands supported by the toolbar macro
config.commands = {
	closeTiddler: {},
	closeOthers: {},
	editTiddler: {},
	saveTiddler: {hideReadOnly: true},
	cancelTiddler: {},
	deleteTiddler: {hideReadOnly: true},
	permalink: {},
	references: {type: "popup"},
	jump: {type: "popup"},
	syncing: {type: "popup"},
	fields: {type: "popup"}
};

// Browser detection... In a very few places, there's nothing else for it but to know what browser we're using.
config.userAgent = navigator.userAgent.toLowerCase();
config.browser = {
	isIE: config.userAgent.indexOf("msie") != -1 && config.userAgent.indexOf("opera") == -1,
	isGecko: config.userAgent.indexOf("gecko") != -1,
	ieVersion: /MSIE (\d.\d)/i.exec(config.userAgent), // config.browser.ieVersion[1], if it exists, will be the IE version string, eg "6.0"
	isSafari: config.userAgent.indexOf("applewebkit") != -1,
	isBadSafari: !((new RegExp("[\u0150\u0170]","g")).test("\u0150")),
	firefoxDate: /gecko\/(\d{8})/i.exec(config.userAgent), // config.browser.firefoxDate[1], if it exists, will be Firefox release date as "YYYYMMDD"
	isOpera: config.userAgent.indexOf("opera") != -1,
	isLinux: config.userAgent.indexOf("linux") != -1,
	isUnix: config.userAgent.indexOf("x11") != -1,
	isMac: config.userAgent.indexOf("mac") != -1,
	isWindows: config.userAgent.indexOf("win") != -1
};

// Basic regular expressions
config.textPrimitives = {
	upperLetter: "[A-Z\u00c0-\u00de\u0150\u0170]",
	lowerLetter: "[a-z0-9_\\-\u00df-\u00ff\u0151\u0171]",
	anyLetter:   "[A-Za-z0-9_\\-\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]",
	anyLetterStrict: "[A-Za-z0-9\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]"
};
if(config.browser.isBadSafari) {
	config.textPrimitives = {
		upperLetter: "[A-Z\u00c0-\u00de]",
		lowerLetter: "[a-z0-9_\\-\u00df-\u00ff]",
		anyLetter:   "[A-Za-z0-9_\\-\u00c0-\u00de\u00df-\u00ff]",
		anyLetterStrict: "[A-Za-z0-9\u00c0-\u00de\u00df-\u00ff]"
	};
}
config.textPrimitives.sliceSeparator = "::";
config.textPrimitives.sectionSeparator = "##";
config.textPrimitives.urlPattern = "(?:file|http|https|mailto|ftp|irc|news|data):[^\\s'\"]+(?:/|\\b)";
config.textPrimitives.unWikiLink = "~";
config.textPrimitives.wikiLink = "(?:(?:" + config.textPrimitives.upperLetter + "+" +
	config.textPrimitives.lowerLetter + "+" +
	config.textPrimitives.upperLetter +
	config.textPrimitives.anyLetter + "*)|(?:" +
	config.textPrimitives.upperLetter + "{2,}" +
	config.textPrimitives.lowerLetter + "+))";

config.textPrimitives.cssLookahead = "(?:(" + config.textPrimitives.anyLetter + "+)\\(([^\\)\\|\\n]+)(?:\\):))|(?:(" + config.textPrimitives.anyLetter + "+):([^;\\|\\n]+);)";
config.textPrimitives.cssLookaheadRegExp = new RegExp(config.textPrimitives.cssLookahead,"mg");

config.textPrimitives.brackettedLink = "\\[\\[([^\\]]+)\\]\\]";
config.textPrimitives.titledBrackettedLink = "\\[\\[([^\\[\\]\\|]+)\\|([^\\[\\]\\|]+)\\]\\]";
config.textPrimitives.tiddlerForcedLinkRegExp = new RegExp("(?:" + config.textPrimitives.titledBrackettedLink + ")|(?:" +
	config.textPrimitives.brackettedLink + ")|(?:" +
	config.textPrimitives.urlPattern + ")","mg");
config.textPrimitives.tiddlerAnyLinkRegExp = new RegExp("("+ config.textPrimitives.wikiLink + ")|(?:" +
	config.textPrimitives.titledBrackettedLink + ")|(?:" +
	config.textPrimitives.brackettedLink + ")|(?:" +
	config.textPrimitives.urlPattern + ")","mg");

config.glyphs = {
	browsers: [
		function() {return config.browser.isIE;},
		function() {return true;}
	],
	currBrowser: null,
	codes: {
		downTriangle: ["\u25BC","\u25BE"],
		downArrow: ["\u2193","\u2193"],
		bentArrowLeft: ["\u2190","\u21A9"],
		bentArrowRight: ["\u2192","\u21AA"]
	}
};

//--
//-- Shadow tiddlers
//--

config.shadowTiddlers = {
	StyleSheet: "",
	MarkupPreHead: "",
	MarkupPostHead: "",
	MarkupPreBody: "",
	MarkupPostBody: "",
	TabTimeline: '<<timeline>>',
	TabAll: '<<list all>>',
	TabTags: '<<allTags excludeLists>>',
	TabMoreMissing: '<<list missing>>',
	TabMoreOrphans: '<<list orphans>>',
	TabMoreShadowed: '<<list shadowed>>',
	AdvancedOptions: '<<options>>',
	PluginManager: '<<plugins>>',
	ToolbarCommands: '|~ViewToolbar|closeTiddler closeOthers +editTiddler > fields syncing permalink references jump|\n|~EditToolbar|+saveTiddler -cancelTiddler deleteTiddler|'
};

//--
//-- Translateable strings
//--

// Strings in "double quotes" should be translated; strings in 'single quotes' should be left alone

merge(config.options,{
	txtUserName: "YourName"});

merge(config.tasks,{
	save: {text: "save", tooltip: "Save your changes to this TiddlyWiki", action: saveChanges},
	sync: {text: "sync", tooltip: "Synchronise changes with other TiddlyWiki files and servers", content: '<<sync>>'},
	importTask: {text: "import", tooltip: "Import tiddlers and plugins from other TiddlyWiki files and servers", content: '<<importTiddlers>>'},
	tweak: {text: "tweak", tooltip: "Tweak the appearance and behaviour of TiddlyWiki", content: '<<options>>'},
	upgrade: {text: "upgrade", tooltip: "Upgrade TiddlyWiki core code", content: '<<upgrade>>'},
	plugins: {text: "plugins", tooltip: "Manage installed plugins", content: '<<plugins>>'}
});

// Options that can be set in the options panel and/or cookies
merge(config.optionsDesc,{
	txtUserName: "Username for signing your edits",
	chkRegExpSearch: "Enable regular expressions for searches",
	chkCaseSensitiveSearch: "Case-sensitive searching",
	chkIncrementalSearch: "Incremental key-by-key searching",
	chkAnimate: "Enable animations",
	chkSaveBackups: "Keep backup file when saving changes",
	chkAutoSave: "Automatically save changes",
	chkGenerateAnRssFeed: "Generate an RSS feed when saving changes",
	chkSaveEmptyTemplate: "Generate an empty template when saving changes",
	chkOpenInNewWindow: "Open external links in a new window",
	chkToggleLinks: "Clicking on links to open tiddlers causes them to close",
	chkHttpReadOnly: "Hide editing features when viewed over HTTP",
	chkForceMinorUpdate: "Don't update modifier username and date when editing tiddlers",
	chkConfirmDelete: "Require confirmation before deleting tiddlers",
	chkInsertTabs: "Use the tab key to insert tab characters instead of moving between fields",
	txtBackupFolder: "Name of folder to use for backups",
	txtMaxEditRows: "Maximum number of rows in edit boxes",
	txtTheme: "Name of the theme to use",
	txtFileSystemCharSet: "Default character set for saving changes (Firefox/Mozilla only)"});

merge(config.messages,{
	customConfigError: "Problems were encountered loading plugins. See PluginManager for details",
	pluginError: "Error: %0",
	pluginDisabled: "Not executed because disabled via 'systemConfigDisable' tag",
	pluginForced: "Executed because forced via 'systemConfigForce' tag",
	pluginVersionError: "Not executed because this plugin needs a newer version of TiddlyWiki",
	nothingSelected: "Nothing is selected. You must select one or more items first",
	savedSnapshotError: "It appears that this TiddlyWiki has been incorrectly saved. Please see http://www.tiddlywiki.com/#Download for details",
	subtitleUnknown: "(unknown)",
	undefinedTiddlerToolTip: "The tiddler '%0' doesn't yet exist",
	shadowedTiddlerToolTip: "The tiddler '%0' doesn't yet exist, but has a pre-defined shadow value",
	tiddlerLinkTooltip: "%0 - %1, %2",
	externalLinkTooltip: "External link to %0",
	noTags: "There are no tagged tiddlers",
	notFileUrlError: "You need to save this TiddlyWiki to a file before you can save changes",
	cantSaveError: "It's not possible to save changes. Possible reasons include:\n- your browser doesn't support saving (Firefox, Internet Explorer, Safari and Opera all work if properly configured)\n- the pathname to your TiddlyWiki file contains illegal characters\n- the TiddlyWiki HTML file has been moved or renamed",
	invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
	backupSaved: "Backup saved",
	backupFailed: "Failed to save backup file",
	rssSaved: "RSS feed saved",
	rssFailed: "Failed to save RSS feed file",
	emptySaved: "Empty template saved",
	emptyFailed: "Failed to save empty template file",
	mainSaved: "Main TiddlyWiki file saved",
	mainFailed: "Failed to save main TiddlyWiki file. Your changes have not been saved",
	macroError: "Error in macro <<\%0>>",
	macroErrorDetails: "Error while executing macro <<\%0>>:\n%1",
	missingMacro: "No such macro",
	overwriteWarning: "A tiddler named '%0' already exists. Choose OK to overwrite it",
	unsavedChangesWarning: "WARNING! There are unsaved changes in TiddlyWiki\n\nChoose OK to save\nChoose CANCEL to discard",
	confirmExit: "--------------------------------\n\nThere are unsaved changes in TiddlyWiki. If you continue you will lose those changes\n\n--------------------------------",
	saveInstructions: "SaveChanges",
	unsupportedTWFormat: "Unsupported TiddlyWiki format '%0'",
	tiddlerSaveError: "Error when saving tiddler '%0'",
	tiddlerLoadError: "Error when loading tiddler '%0'",
	wrongSaveFormat: "Cannot save with storage format '%0'. Using standard format for save.",
	invalidFieldName: "Invalid field name %0",
	fieldCannotBeChanged: "Field '%0' cannot be changed",
	loadingMissingTiddler: "Attempting to retrieve the tiddler '%0' from the '%1' server at:\n\n'%2' in the workspace '%3'",
	upgradeDone: "The upgrade to version %0 is now complete\n\nClick 'OK' to reload the newly upgraded TiddlyWiki"});

merge(config.messages.messageClose,{
	text: "close",
	tooltip: "close this message area"});

config.messages.backstage = {
	open: {text: "backstage", tooltip: "Open the backstage area to perform authoring and editing tasks"},
	close: {text: "close", tooltip: "Close the backstage area"},
	prompt: "backstage: ",
	decal: {
		edit: {text: "edit", tooltip: "Edit the tiddler '%0'"}
	}
};

config.messages.listView = {
	tiddlerTooltip: "Click for the full text of this tiddler",
	previewUnavailable: "(preview not available)"
};

config.messages.dates.months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November","December"];
config.messages.dates.days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
config.messages.dates.shortMonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
config.messages.dates.shortDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
// suffixes for dates, eg "1st","2nd","3rd"..."30th","31st"
config.messages.dates.daySuffixes = ["st","nd","rd","th","th","th","th","th","th","th",
		"th","th","th","th","th","th","th","th","th","th",
		"st","nd","rd","th","th","th","th","th","th","th",
		"st"];
config.messages.dates.am = "am";
config.messages.dates.pm = "pm";

merge(config.messages.tiddlerPopup,{
	});

merge(config.views.wikified.tag,{
	labelNoTags: "no tags",
	labelTags: "tags: ",
	openTag: "Open tag '%0'",
	tooltip: "Show tiddlers tagged with '%0'",
	openAllText: "Open all",
	openAllTooltip: "Open all of these tiddlers",
	popupNone: "No other tiddlers tagged with '%0'"});

merge(config.views.wikified,{
	defaultText: "The tiddler '%0' doesn't yet exist. Double-click to create it",
	defaultModifier: "(missing)",
	shadowModifier: "(built-in shadow tiddler)",
	dateFormat: "DD MMM YYYY",
	createdPrompt: "created"});

merge(config.views.editor,{
	tagPrompt: "Type tags separated with spaces, [[use double square brackets]] if necessary, or add existing",
	defaultText: "Type the text for '%0'"});

merge(config.views.editor.tagChooser,{
	text: "tags",
	tooltip: "Choose existing tags to add to this tiddler",
	popupNone: "There are no tags defined",
	tagTooltip: "Add the tag '%0'"});

merge(config.messages,{
	sizeTemplates:
		[
		{unit: 1024*1024*1024, template: "%0\u00a0GB"},
		{unit: 1024*1024, template: "%0\u00a0MB"},
		{unit: 1024, template: "%0\u00a0KB"},
		{unit: 1, template: "%0\u00a0B"}
		]});

merge(config.macros.search,{
	label: "search",
	prompt: "Search this TiddlyWiki",
	accessKey: "F",
	successMsg: "%0 tiddlers found matching %1",
	failureMsg: "No tiddlers found matching %0"});

merge(config.macros.tagging,{
	label: "tagging: ",
	labelNotTag: "not tagging",
	tooltip: "List of tiddlers tagged with '%0'"});

merge(config.macros.timeline,{
	dateFormat: "DD MMM YYYY"});

merge(config.macros.allTags,{
	tooltip: "Show tiddlers tagged with '%0'",
	noTags: "There are no tagged tiddlers"});

config.macros.list.all.prompt = "All tiddlers in alphabetical order";
config.macros.list.missing.prompt = "Tiddlers that have links to them but are not defined";
config.macros.list.orphans.prompt = "Tiddlers that are not linked to from any other tiddlers";
config.macros.list.shadowed.prompt = "Tiddlers shadowed with default contents";
config.macros.list.touched.prompt = "Tiddlers that have been modified locally";

merge(config.macros.closeAll,{
	label: "close all",
	prompt: "Close all displayed tiddlers (except any that are being edited)"});

merge(config.macros.permaview,{
	label: "permaview",
	prompt: "Link to an URL that retrieves all the currently displayed tiddlers"});

merge(config.macros.saveChanges,{
	label: "save changes",
	prompt: "Save all tiddlers to create a new TiddlyWiki",
	accessKey: "S"});

merge(config.macros.newTiddler,{
	label: "new tiddler",
	prompt: "Create a new tiddler",
	title: "New Tiddler",
	accessKey: "N"});

merge(config.macros.newJournal,{
	label: "new journal",
	prompt: "Create a new tiddler from the current date and time",
	accessKey: "J"});

merge(config.macros.options,{
	wizardTitle: "Tweak advanced options",
	step1Title: "These options are saved in cookies in your browser",
	step1Html: "<input type='hidden' name='markList'></input><br><input type='checkbox' checked='false' name='chkUnknown'>Show unknown options</input>",
	unknownDescription: "//(unknown)//",
	listViewTemplate: {
		columns: [
			{name: 'Option', field: 'option', title: "Option", type: 'String'},
			{name: 'Description', field: 'description', title: "Description", type: 'WikiText'},
			{name: 'Name', field: 'name', title: "Name", type: 'String'}
			],
		rowClasses: [
			{className: 'lowlight', field: 'lowlight'}
			]}
	});

merge(config.macros.plugins,{
	wizardTitle: "Manage plugins",
	step1Title: "Currently loaded plugins",
	step1Html: "<input type='hidden' name='markList'></input>", // DO NOT TRANSLATE
	skippedText: "(This plugin has not been executed because it was added since startup)",
	noPluginText: "There are no plugins installed",
	confirmDeleteText: "Are you sure you want to delete these plugins:\n\n%0",
	removeLabel: "remove systemConfig tag",
	removePrompt: "Remove systemConfig tag",
	deleteLabel: "delete",
	deletePrompt: "Delete these tiddlers forever",
	listViewTemplate: {
		columns: [
			{name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
			{name: 'Tiddler', field: 'tiddler', title: "Tiddler", type: 'Tiddler'},
			{name: 'Description', field: 'Description', title: "Description", type: 'String'},
			{name: 'Version', field: 'Version', title: "Version", type: 'String'},
			{name: 'Size', field: 'size', tiddlerLink: 'size', title: "Size", type: 'Size'},
			{name: 'Forced', field: 'forced', title: "Forced", tag: 'systemConfigForce', type: 'TagCheckbox'},
			{name: 'Disabled', field: 'disabled', title: "Disabled", tag: 'systemConfigDisable', type: 'TagCheckbox'},
			{name: 'Executed', field: 'executed', title: "Loaded", type: 'Boolean', trueText: "Yes", falseText: "No"},
			{name: 'Startup Time', field: 'startupTime', title: "Startup Time", type: 'String'},
			{name: 'Error', field: 'error', title: "Status", type: 'Boolean', trueText: "Error", falseText: "OK"},
			{name: 'Log', field: 'log', title: "Log", type: 'StringList'}
			],
		rowClasses: [
			{className: 'error', field: 'error'},
			{className: 'warning', field: 'warning'}
			]}
	});

merge(config.macros.toolbar,{
	moreLabel: "more",
	morePrompt: "Show additional commands",
	lessLabel: "less",
	lessPrompt: "Hide additional commands",
	separator: "|"
	});

merge(config.macros.refreshDisplay,{
	label: "refresh",
	prompt: "Redraw the entire TiddlyWiki display"
	});

merge(config.macros.importTiddlers,{
	readOnlyWarning: "You cannot import into a read-only TiddlyWiki file. Try opening it from a file:// URL",
	wizardTitle: "Import tiddlers from another file or server",
	step1Title: "Step 1: Locate the server or TiddlyWiki file",
	step1Html: "Specify the type of the server: <select name='selTypes'><option value=''>Choose...</option></select><br>Enter the URL or pathname here: <input type='text' size=50 name='txtPath'><br>...or browse for a file: <input type='file' size=50 name='txtBrowse'><br><hr>...or select a pre-defined feed: <select name='selFeeds'><option value=''>Choose...</option></select>",
	openLabel: "open",
	openPrompt: "Open the connection to this file or server",
	openError: "There were problems fetching the tiddlywiki file",
	statusOpenHost: "Opening the host",
	statusGetWorkspaceList: "Getting the list of available workspaces",
	step2Title: "Step 2: Choose the workspace",
	step2Html: "Enter a workspace name: <input type='text' size=50 name='txtWorkspace'><br>...or select a workspace: <select name='selWorkspace'><option value=''>Choose...</option></select>",
	cancelLabel: "cancel",
	cancelPrompt: "Cancel this import",
	statusOpenWorkspace: "Opening the workspace",
	statusGetTiddlerList: "Getting the list of available tiddlers",
	errorGettingTiddlerList: "Error getting list of tiddlers, click Cancel to try again",
	step3Title: "Step 3: Choose the tiddlers to import",
	step3Html: "<input type='hidden' name='markList'></input><br><input type='checkbox' checked='true' name='chkSync'>Keep these tiddlers linked to this server so that you can synchronise subsequent changes</input><br><input type='checkbox' name='chkSave'>Save the details of this server in a 'systemServer' tiddler called:</input> <input type='text' size=25 name='txtSaveTiddler'>",
	importLabel: "import",
	importPrompt: "Import these tiddlers",
	confirmOverwriteText: "Are you sure you want to overwrite these tiddlers:\n\n%0",
	step4Title: "Step 4: Importing %0 tiddler(s)",
	step4Html: "<input type='hidden' name='markReport'></input>", // DO NOT TRANSLATE
	doneLabel: "done",
	donePrompt: "Close this wizard",
	statusDoingImport: "Importing tiddlers",
	statusDoneImport: "All tiddlers imported",
	systemServerNamePattern: "%2 on %1",
	systemServerNamePatternNoWorkspace: "%1",
	confirmOverwriteSaveTiddler: "The tiddler '%0' already exists. Click 'OK' to overwrite it with the details of this server, or 'Cancel' to leave it unchanged",
	serverSaveTemplate: "|''Type:''|%0|\n|''URL:''|%1|\n|''Workspace:''|%2|\n\nThis tiddler was automatically created to record the details of this server",
	serverSaveModifier: "(System)",
	listViewTemplate: {
		columns: [
			{name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
			{name: 'Tiddler', field: 'tiddler', title: "Tiddler", type: 'Tiddler'},
			{name: 'Size', field: 'size', tiddlerLink: 'size', title: "Size", type: 'Size'},
			{name: 'Tags', field: 'tags', title: "Tags", type: 'Tags'}
			],
		rowClasses: [
			]}
	});

merge(config.macros.upgrade,{
	wizardTitle: "Upgrade TiddlyWiki core code",
	step1Title: "Update or repair this TiddlyWiki to the latest release",
	step1Html: "You are about to upgrade to the latest release of the TiddlyWiki core code (from <a href='%0' class='externalLink' target='_blank'>%1</a>). Your content will be preserved across the upgrade.<br><br>Note that core upgrades have been known to interfere with older plugins. If you run into problems with the upgraded file, see <a href='http://www.tiddlywiki.org/wiki/CoreUpgrades' class='externalLink' target='_blank'>http://www.tiddlywiki.org/wiki/CoreUpgrades</a>",
	errorCantUpgrade: "Unable to upgrade this TiddlyWiki. You can only perform upgrades on TiddlyWiki files stored locally",
	errorNotSaved: "You must save changes before you can perform an upgrade",
	step2Title: "Confirm the upgrade details",
	step2Html_downgrade: "You are about to downgrade to TiddlyWiki version %0 from %1.<br><br>Downgrading to an earlier version of the core code is not recommended",
	step2Html_restore: "This TiddlyWiki appears to be already using the latest version of the core code (%0).<br><br>You can continue to upgrade anyway to ensure that the core code hasn't been corrupted or damaged",
	step2Html_upgrade: "You are about to upgrade to TiddlyWiki version %0 from %1",
	upgradeLabel: "upgrade",
	upgradePrompt: "Prepare for the upgrade process",
	statusPreparingBackup: "Preparing backup",
	statusSavingBackup: "Saving backup file",
	errorSavingBackup: "There was a problem saving the backup file",
	statusLoadingCore: "Loading core code",
	errorLoadingCore: "Error loading the core code",
	errorCoreFormat: "Error with the new core code",
	statusSavingCore: "Saving the new core code",
	statusReloadingCore: "Reloading the new core code",
	startLabel: "start",
	startPrompt: "Start the upgrade process",
	cancelLabel: "cancel",
	cancelPrompt: "Cancel the upgrade process",
	step3Title: "Upgrade cancelled",
	step3Html: "You have cancelled the upgrade process"
	});

merge(config.macros.sync,{
	listViewTemplate: {
		columns: [
			{name: 'Selected', field: 'selected', rowName: 'title', type: 'Selector'},
			{name: 'Tiddler', field: 'tiddler', title: "Tiddler", type: 'Tiddler'},
			{name: 'Server Type', field: 'serverType', title: "Server type", type: 'String'},
			{name: 'Server Host', field: 'serverHost', title: "Server host", type: 'String'},
			{name: 'Server Workspace', field: 'serverWorkspace', title: "Server workspace", type: 'String'},
			{name: 'Status', field: 'status', title: "Synchronisation status", type: 'String'},
			{name: 'Server URL', field: 'serverUrl', title: "Server URL", text: "View", type: 'Link'}
			],
		rowClasses: [
			],
		buttons: [
			{caption: "Sync these tiddlers", name: 'sync'}
			]},
	wizardTitle: "Synchronize with external servers and files",
	step1Title: "Choose the tiddlers you want to synchronize",
	step1Html: "<input type='hidden' name='markList'></input>", // DO NOT TRANSLATE
	syncLabel: "sync",
	syncPrompt: "Sync these tiddlers",
	hasChanged: "Changed while unplugged",
	hasNotChanged: "Unchanged while unplugged",
	syncStatusList: {
		none: {text: "...", display:null, className:'notChanged'},
		changedServer: {text: "Changed on server", display:null, className:'changedServer'},
		changedLocally: {text: "Changed while unplugged", display:null, className:'changedLocally'},
		changedBoth: {text: "Changed while unplugged and on server", display:null, className:'changedBoth'},
		notFound: {text: "Not found on server", display:null, className:'notFound'},
		putToServer: {text: "Saved update on server", display:null, className:'putToServer'},
		gotFromServer: {text: "Retrieved update from server", display:null, className:'gotFromServer'}
		}
	});

merge(config.macros.annotations,{
	});

merge(config.commands.closeTiddler,{
	text: "close",
	tooltip: "Close this tiddler"});

merge(config.commands.closeOthers,{
	text: "close others",
	tooltip: "Close all other tiddlers"});

merge(config.commands.editTiddler,{
	text: "edit",
	tooltip: "Edit this tiddler",
	readOnlyText: "view",
	readOnlyTooltip: "View the source of this tiddler"});

merge(config.commands.saveTiddler,{
	text: "done",
	tooltip: "Save changes to this tiddler"});

merge(config.commands.cancelTiddler,{
	text: "cancel",
	tooltip: "Undo changes to this tiddler",
	warning: "Are you sure you want to abandon your changes to '%0'?",
	readOnlyText: "done",
	readOnlyTooltip: "View this tiddler normally"});

merge(config.commands.deleteTiddler,{
	text: "delete",
	tooltip: "Delete this tiddler",
	warning: "Are you sure you want to delete '%0'?"});

merge(config.commands.permalink,{
	text: "permalink",
	tooltip: "Permalink for this tiddler"});

merge(config.commands.references,{
	text: "references",
	tooltip: "Show tiddlers that link to this one",
	popupNone: "No references"});

merge(config.commands.jump,{
	text: "jump",
	tooltip: "Jump to another open tiddler"});

merge(config.commands.syncing,{
	text: "syncing",
	tooltip: "Control synchronisation of this tiddler with a server or external file",
	currentlySyncing: "<div>Currently syncing via <span class='popupHighlight'>'%0'</span> to:</"+"div><div>host: <span class='popupHighlight'>%1</span></"+"div><div>workspace: <span class='popupHighlight'>%2</span></"+"div>", // Note escaping of closing <div> tag
	notCurrentlySyncing: "Not currently syncing",
	captionUnSync: "Stop synchronising this tiddler",
	chooseServer: "Synchronise this tiddler with another server:",
	currServerMarker: "\u25cf ",
	notCurrServerMarker: "  "});

merge(config.commands.fields,{
	text: "fields",
	tooltip: "Show the extended fields of this tiddler",
	emptyText: "There are no extended fields for this tiddler",
	listViewTemplate: {
		columns: [
			{name: 'Field', field: 'field', title: "Field", type: 'String'},
			{name: 'Value', field: 'value', title: "Value", type: 'String'}
			],
		rowClasses: [
			],
		buttons: [
			]}});

merge(config.shadowTiddlers,{
	DefaultTiddlers: "[[GettingStarted]]",
	MainMenu: "[[GettingStarted]]",
	SiteTitle: "My TiddlyWiki",
	SiteSubtitle: "a reusable non-linear personal web notebook",
	SiteUrl: "http://www.tiddlywiki.com/",
	SideBarOptions: '<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal "DD MMM YYYY" "journal">><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel "options \u00bb" "Change TiddlyWiki advanced options">>',
	SideBarTabs: '<<tabs txtMainTab "Timeline" "Timeline" TabTimeline "All" "All tiddlers" TabAll "Tags" "All tags" TabTags "More" "More lists" TabMore>>',
	TabMore: '<<tabs txtMoreTab "Missing" "Missing tiddlers" TabMoreMissing "Orphans" "Orphaned tiddlers" TabMoreOrphans "Shadowed" "Shadowed tiddlers" TabMoreShadowed>>'
	});

merge(config.annotations,{
	AdvancedOptions: "This shadow tiddler provides access to several advanced options",
	ColorPalette: "These values in this shadow tiddler determine the colour scheme of the ~TiddlyWiki user interface",
	DefaultTiddlers: "The tiddlers listed in this shadow tiddler will be automatically displayed when ~TiddlyWiki starts up",
	EditTemplate: "The HTML template in this shadow tiddler determines how tiddlers look while they are being edited",
	GettingStarted: "This shadow tiddler provides basic usage instructions",
	ImportTiddlers: "This shadow tiddler provides access to importing tiddlers",
	MainMenu: "This shadow tiddler is used as the contents of the main menu in the left-hand column of the screen",
	MarkupPreHead: "This tiddler is inserted at the top of the <head> section of the TiddlyWiki HTML file",
	MarkupPostHead: "This tiddler is inserted at the bottom of the <head> section of the TiddlyWiki HTML file",
	MarkupPreBody: "This tiddler is inserted at the top of the <body> section of the TiddlyWiki HTML file",
	MarkupPostBody: "This tiddler is inserted at the end of the <body> section of the TiddlyWiki HTML file immediately after the script block",
	OptionsPanel: "This shadow tiddler is used as the contents of the options panel slider in the right-hand sidebar",
	PageTemplate: "The HTML template in this shadow tiddler determines the overall ~TiddlyWiki layout",
	PluginManager: "This shadow tiddler provides access to the plugin manager",
	SideBarOptions: "This shadow tiddler is used as the contents of the option panel in the right-hand sidebar",
	SideBarTabs: "This shadow tiddler is used as the contents of the tabs panel in the right-hand sidebar",
	SiteSubtitle: "This shadow tiddler is used as the second part of the page title",
	SiteTitle: "This shadow tiddler is used as the first part of the page title",
	SiteUrl: "This shadow tiddler should be set to the full target URL for publication",
	StyleSheetColors: "This shadow tiddler contains CSS definitions related to the color of page elements. ''DO NOT EDIT THIS TIDDLER'', instead make your changes in the StyleSheet shadow tiddler",
	StyleSheet: "This tiddler can contain custom CSS definitions",
	StyleSheetLayout: "This shadow tiddler contains CSS definitions related to the layout of page elements. ''DO NOT EDIT THIS TIDDLER'', instead make your changes in the StyleSheet shadow tiddler",
	StyleSheetLocale: "This shadow tiddler contains CSS definitions related to the translation locale",
	StyleSheetPrint: "This shadow tiddler contains CSS definitions for printing",
	TabAll: "This shadow tiddler contains the contents of the 'All' tab in the right-hand sidebar",
	TabMore: "This shadow tiddler contains the contents of the 'More' tab in the right-hand sidebar",
	TabMoreMissing: "This shadow tiddler contains the contents of the 'Missing' tab in the right-hand sidebar",
	TabMoreOrphans: "This shadow tiddler contains the contents of the 'Orphans' tab in the right-hand sidebar",
	TabMoreShadowed: "This shadow tiddler contains the contents of the 'Shadowed' tab in the right-hand sidebar",
	TabTags: "This shadow tiddler contains the contents of the 'Tags' tab in the right-hand sidebar",
	TabTimeline: "This shadow tiddler contains the contents of the 'Timeline' tab in the right-hand sidebar",
	ToolbarCommands: "This shadow tiddler determines which commands are shown in tiddler toolbars",
	ViewTemplate: "The HTML template in this shadow tiddler determines how tiddlers look"
	});

//--
//-- Main
//--

var params = null; // Command line parameters
var store = null; // TiddlyWiki storage
var story = null; // Main story
var formatter = null; // Default formatters for the wikifier
var anim = typeof Animator == "function" ? new Animator() : null; // Animation engine
var readOnly = false; // Whether we're in readonly mode
var highlightHack = null; // Embarrassing hack department...
var hadConfirmExit = false; // Don't warn more than once
var safeMode = false; // Disable all plugins and cookies
var showBackstage; // Whether to include the backstage area
var installedPlugins = []; // Information filled in when plugins are executed
var startingUp = false; // Whether we're in the process of starting up
var pluginInfo,tiddler; // Used to pass information to plugins in loadPlugins()

// Whether to use the JavaSaver applet
var useJavaSaver = (config.browser.isSafari || config.browser.isOpera) && (document.location.toString().substr(0,4) != "http");

// Starting up
function main()
{
	var t10,t9,t8,t7,t6,t5,t4,t3,t2,t1,t0 = new Date();
	startingUp = true;
	jQuery.noConflict();
	window.onbeforeunload = function(e) {if(window.confirmExit) return confirmExit();};
	params = getParameters();
	if(params)
		params = params.parseParams("open",null,false);
	store = new TiddlyWiki();
	invokeParamifier(params,"oninit");
	story = new Story("tiddlerDisplay","tiddler");
	addEvent(document,"click",Popup.onDocumentClick);
	saveTest();
	loadOptionsCookie();
	for(var s=0; s<config.notifyTiddlers.length; s++)
		store.addNotification(config.notifyTiddlers[s].name,config.notifyTiddlers[s].notify);
	t1 = new Date();
	loadShadowTiddlers();
	jQuery().trigger("loadShadows");
	t2 = new Date();
	store.loadFromDiv("storeArea","store",true);
	jQuery().trigger("loadTiddlers");
	t3 = new Date();
	invokeParamifier(params,"onload");
	t4 = new Date();
	readOnly = (window.location.protocol == "file:") ? false : config.options.chkHttpReadOnly;
	var pluginProblem = loadPlugins();
	jQuery().trigger("loadPlugins");
	t5 = new Date();
	formatter = new Formatter(config.formatters);
	invokeParamifier(params,"onconfig");
	story.switchTheme(config.options.txtTheme);
	showBackstage = !readOnly;
	t6 = new Date();
	for(var m in config.macros) {
		if(config.macros[m].init)
			config.macros[m].init();
	}
	t7 = new Date();
	store.notifyAll();
	t8 = new Date();
	restart();
	refreshDisplay();
	t9 = new Date();
	if(pluginProblem) {
		story.displayTiddler(null,"PluginManager");
		displayMessage(config.messages.customConfigError);
	}
	if(showBackstage)
		backstage.init();
	t10 = new Date();
	if(config.options.chkDisplayInstrumentation) {
		displayMessage("LoadShadows " + (t2-t1) + " ms");
		displayMessage("LoadFromDiv " + (t3-t2) + " ms");
		displayMessage("LoadPlugins " + (t5-t4) + " ms");
		displayMessage("Macro init " + (t7-t6) + " ms");
		displayMessage("Notify " + (t8-t7) + " ms");
		displayMessage("Restart " + (t9-t8) + " ms");
		displayMessage("Total: " + (t10-t0) + " ms");
	}
	startingUp = false;
	jQuery().trigger("startup");
}

// Called on unload. All functions called conditionally since they themselves may have been unloaded.
function unload()
{
	if(window.checkUnsavedChanges)
		checkUnsavedChanges();
	if(window.scrubNodes)
		scrubNodes(document.body);
}

// Restarting
function restart()
{
	invokeParamifier(params,"onstart");
	if(story.isEmpty()) {
		story.displayDefaultTiddlers();
	}
	window.scrollTo(0,0);
}

function saveTest()
{
	var s = document.getElementById("saveTest");
	if(s.hasChildNodes())
		alert(config.messages.savedSnapshotError);
	s.appendChild(document.createTextNode("savetest"));
}

function loadShadowTiddlers()
{
	var shadows = new TiddlyWiki();
	shadows.loadFromDiv("shadowArea","shadows",true);
	shadows.forEachTiddler(function(title,tiddler){config.shadowTiddlers[title] = tiddler.text;});
	delete shadows;
}

function loadPlugins()
{
	if(safeMode)
		return false;
	var tiddlers = store.getTaggedTiddlers("systemConfig");
	var toLoad = [];
	var nLoaded = 0;
	var map = {};
	var nPlugins = tiddlers.length;
	installedPlugins = [];
	for(var i=0; i<nPlugins; i++) {
		var p = getPluginInfo(tiddlers[i]);
		installedPlugins[i] = p;
		var n = p.Name;
		if(n)
			map[n] = p;
		n = p.Source;
		if(n)
			map[n] = p;
	}
	var visit = function(p) {
		if(!p || p.done)
			return;
		p.done = 1;
		var reqs = p.Requires;
		if(reqs) {
			reqs = reqs.readBracketedList();
			for(var i=0; i<reqs.length; i++)
				visit(map[reqs[i]]);
		}
		toLoad.push(p);
	};
	for(i=0; i<nPlugins; i++)
		visit(installedPlugins[i]);
	for(i=0; i<toLoad.length; i++) {
		p = toLoad[i];
		pluginInfo = p;
		tiddler = p.tiddler;
		if(isPluginExecutable(p)) {
			if(isPluginEnabled(p)) {
				p.executed = true;
				var startTime = new Date();
				try {
					if(tiddler.text)
						window.eval(tiddler.text);
					nLoaded++;
				} catch(ex) {
					p.log.push(config.messages.pluginError.format([exceptionText(ex)]));
					p.error = true;
				}
				pluginInfo.startupTime = String((new Date()) - startTime) + "ms";
			} else {
				nPlugins--;
			}
		} else {
			p.warning = true;
		}
	}
	return nLoaded != nPlugins;
}

function getPluginInfo(tiddler)
{
	var p = store.getTiddlerSlices(tiddler.title,["Name","Description","Version","Requires","CoreVersion","Date","Source","Author","License","Browsers"]);
	p.tiddler = tiddler;
	p.title = tiddler.title;
	p.log = [];
	return p;
}

// Check that a particular plugin is valid for execution
function isPluginExecutable(plugin)
{
	if(plugin.tiddler.isTagged("systemConfigForce")) {
		plugin.log.push(config.messages.pluginForced);
		return true;
	}
	if(plugin["CoreVersion"]) {
		var coreVersion = plugin["CoreVersion"].split(".");
		var w = parseInt(coreVersion[0],10) - version.major;
		if(w == 0 && coreVersion[1])
			w = parseInt(coreVersion[1],10) - version.minor;
		if(w == 0 && coreVersion[2])
			w = parseInt(coreVersion[2],10) - version.revision;
		if(w > 0) {
			plugin.log.push(config.messages.pluginVersionError);
			return false;
		}
	}
	return true;
}

function isPluginEnabled(plugin)
{
	if(plugin.tiddler.isTagged("systemConfigDisable")) {
		plugin.log.push(config.messages.pluginDisabled);
		return false;
	}
	return true;
}

function invokeMacro(place,macro,params,wikifier,tiddler)
{
	try {
		var m = config.macros[macro];
		if(m && m.handler) {
			var tiddlerElem = story.findContainingTiddler(place);
			window.tiddler = tiddlerElem ? store.getTiddler(tiddlerElem.getAttribute("tiddler")) : null;
			window.place = place;
			m.handler(place,macro,params.readMacroParams(),wikifier,params,tiddler);
		} else {
			createTiddlyError(place,config.messages.macroError.format([macro]),config.messages.macroErrorDetails.format([macro,config.messages.missingMacro]));
		}
	} catch(ex) {
		createTiddlyError(place,config.messages.macroError.format([macro]),config.messages.macroErrorDetails.format([macro,ex.toString()]));
	}
}

//--
//-- Paramifiers
//--

function getParameters()
{
	var p = null;
	if(window.location.hash) {
		p = decodeURIComponent(window.location.hash.substr(1));
		if(config.browser.firefoxDate != null && config.browser.firefoxDate[1] < "20051111")
			p = convertUTF8ToUnicode(p);
	}
	return p;
}

function invokeParamifier(params,handler)
{
	if(!params || params.length == undefined || params.length <= 1)
		return;
	for(var i=1; i<params.length; i++) {
		var p = config.paramifiers[params[i].name];
		if(p && p[handler] instanceof Function)
			p[handler](params[i].value);
		else {
			var h = config.optionHandlers[params[i].name.substr(0,3)];
			if(h && h.set instanceof Function)
				h.set(params[i].name,params[i].value);
		}
	}
}

config.paramifiers = {};

config.paramifiers.start = {
	oninit: function(v) {
		safeMode = v.toLowerCase() == "safe";
	}
};

config.paramifiers.open = {
	onstart: function(v) {
		if(!readOnly || store.tiddlerExists(v) || store.isShadowTiddler(v))
			story.displayTiddler("bottom",v,null,false,null);
	}
};

config.paramifiers.story = {
	onstart: function(v) {
		var list = store.getTiddlerText(v,"").parseParams("open",null,false);
		invokeParamifier(list,"onstart");
	}
};

config.paramifiers.search = {
	onstart: function(v) {
		story.search(v,false,false);
	}
};

config.paramifiers.searchRegExp = {
	onstart: function(v) {
		story.prototype.search(v,false,true);
	}
};

config.paramifiers.tag = {
	onstart: function(v) {
		story.displayTiddlers(null,store.filterTiddlers("[tag["+v+"]]"),null,false,null);
	}
};

config.paramifiers.newTiddler = {
	onstart: function(v) {
		if(!readOnly) {
			story.displayTiddler(null,v,DEFAULT_EDIT_TEMPLATE);
			story.focusTiddler(v,"text");
		}
	}
};

config.paramifiers.newJournal = {
	onstart: function(v) {
		if(!readOnly) {
			var now = new Date();
			var title = now.formatString(v.trim());
			story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE);
			story.focusTiddler(title,"text");
		}
	}
};

config.paramifiers.readOnly = {
	onconfig: function(v) {
		var p = v.toLowerCase();
		readOnly = p == "yes" ? true : (p == "no" ? false : readOnly);
	}
};

config.paramifiers.theme = {
	onconfig: function(v) {
		story.switchTheme(v);
	}
};

config.paramifiers.upgrade = {
	onstart: function(v) {
		upgradeFrom(v);
	}
};

config.paramifiers.recent= {
	onstart: function(v) {
		var titles=[];
		var tiddlers=store.getTiddlers("modified","excludeLists").reverse();
		for(var i=0; i<v && i<tiddlers.length; i++)
			titles.push(tiddlers[i].title);
		story.displayTiddlers(null,titles);
	}
};

config.paramifiers.filter = {
	onstart: function(v) {
		story.displayTiddlers(null,store.filterTiddlers(v),null,false);
	}
};

//--
//-- Formatter helpers
//--

function Formatter(formatters)
{
	this.formatters = [];
	var pattern = [];
	for(var n=0; n<formatters.length; n++) {
		pattern.push("(" + formatters[n].match + ")");
		this.formatters.push(formatters[n]);
	}
	this.formatterRegExp = new RegExp(pattern.join("|"),"mg");
}

config.formatterHelpers = {

	createElementAndWikify: function(w)
	{
		w.subWikifyTerm(createTiddlyElement(w.output,this.element),this.termRegExp);
	},

	inlineCssHelper: function(w)
	{
		var styles = [];
		config.textPrimitives.cssLookaheadRegExp.lastIndex = w.nextMatch;
		var lookaheadMatch = config.textPrimitives.cssLookaheadRegExp.exec(w.source);
		while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) {
			var s,v;
			if(lookaheadMatch[1]) {
				s = lookaheadMatch[1].unDash();
				v = lookaheadMatch[2];
			} else {
				s = lookaheadMatch[3].unDash();
				v = lookaheadMatch[4];
			}
			if(s=="bgcolor")
				s = "backgroundColor";
			styles.push({style: s, value: v});
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
			config.textPrimitives.cssLookaheadRegExp.lastIndex = w.nextMatch;
			lookaheadMatch = config.textPrimitives.cssLookaheadRegExp.exec(w.source);
		}
		return styles;
	},

	applyCssHelper: function(e,styles)
	{
		for(var t=0; t< styles.length; t++) {
			try {
				e.style[styles[t].style] = styles[t].value;
			} catch (ex) {
			}
		}
	},

	enclosedTextHelper: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var text = lookaheadMatch[1];
			if(config.browser.isIE)
				text = text.replace(/\n/g,"\r");
			createTiddlyElement(w.output,this.element,null,null,text);
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	},

	isExternalLink: function(link)
	{
		if(store.tiddlerExists(link) || store.isShadowTiddler(link)) {
			return false;
		}
		var urlRegExp = new RegExp(config.textPrimitives.urlPattern,"mg");
		if(urlRegExp.exec(link)) {
			return true;
		}
		if(link.indexOf(".")!=-1 || link.indexOf("\\")!=-1 || link.indexOf("/")!=-1 || link.indexOf("#")!=-1) {
			return true;
		}
		return false;
	}

};

//--
//-- Standard formatters
//--

config.formatters = [
{
	name: "table",
	match: "^\\|(?:[^\\n]*)\\|(?:[fhck]?)$",
	lookaheadRegExp: /^\|([^\n]*)\|([fhck]?)$/mg,
	rowTermRegExp: /(\|(?:[fhck]?)$\n?)/mg,
	cellRegExp: /(?:\|([^\n\|]*)\|)|(\|[fhck]?$\n?)/mg,
	cellTermRegExp: /((?:\x20*)\|)/mg,
	rowTypes: {"c":"caption", "h":"thead", "":"tbody", "f":"tfoot"},
	handler: function(w)
	{
		var table = createTiddlyElement(w.output,"table",null,"twtable");
		var prevColumns = [];
		var currRowType = null;
		var rowContainer;
		var rowCount = 0;
		w.nextMatch = w.matchStart;
		this.lookaheadRegExp.lastIndex = w.nextMatch;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) {
			var nextRowType = lookaheadMatch[2];
			if(nextRowType == "k") {
				table.className = lookaheadMatch[1];
				w.nextMatch += lookaheadMatch[0].length+1;
			} else {
				if(nextRowType != currRowType) {
					rowContainer = createTiddlyElement(table,this.rowTypes[nextRowType]);
					currRowType = nextRowType;
				}
				if(currRowType == "c") {
					// Caption
					w.nextMatch++;
					if(rowContainer != table.firstChild)
						table.insertBefore(rowContainer,table.firstChild);
					rowContainer.setAttribute("align",rowCount == 0?"top":"bottom");
					w.subWikifyTerm(rowContainer,this.rowTermRegExp);
				} else {
					var theRow = createTiddlyElement(rowContainer,"tr",null,(rowCount&1)?"oddRow":"evenRow");
					theRow.onmouseover = function() {addClass(this,"hoverRow");};
					theRow.onmouseout = function() {removeClass(this,"hoverRow");};
					this.rowHandler(w,theRow,prevColumns);
					rowCount++;
				}
			}
			this.lookaheadRegExp.lastIndex = w.nextMatch;
			lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		}
	},
	rowHandler: function(w,e,prevColumns)
	{
		var col = 0;
		var colSpanCount = 1;
		var prevCell = null;
		this.cellRegExp.lastIndex = w.nextMatch;
		var cellMatch = this.cellRegExp.exec(w.source);
		while(cellMatch && cellMatch.index == w.nextMatch) {
			if(cellMatch[1] == "~") {
				// Rowspan
				var last = prevColumns[col];
				if(last) {
					last.rowSpanCount++;
					last.element.setAttribute("rowspan",last.rowSpanCount);
					last.element.setAttribute("rowSpan",last.rowSpanCount); // Needed for IE
					last.element.valign = "center";
				}
				w.nextMatch = this.cellRegExp.lastIndex-1;
			} else if(cellMatch[1] == ">") {
				// Colspan
				colSpanCount++;
				w.nextMatch = this.cellRegExp.lastIndex-1;
			} else if(cellMatch[2]) {
				// End of row
				if(prevCell && colSpanCount > 1) {
					prevCell.setAttribute("colspan",colSpanCount);
					prevCell.setAttribute("colSpan",colSpanCount); // Needed for IE
				}
				w.nextMatch = this.cellRegExp.lastIndex;
				break;
			} else {
				// Cell
				w.nextMatch++;
				var styles = config.formatterHelpers.inlineCssHelper(w);
				var spaceLeft = false;
				var chr = w.source.substr(w.nextMatch,1);
				while(chr == " ") {
					spaceLeft = true;
					w.nextMatch++;
					chr = w.source.substr(w.nextMatch,1);
				}
				var cell;
				if(chr == "!") {
					cell = createTiddlyElement(e,"th");
					w.nextMatch++;
				} else {
					cell = createTiddlyElement(e,"td");
				}
				prevCell = cell;
				prevColumns[col] = {rowSpanCount:1,element:cell};
				if(colSpanCount > 1) {
					cell.setAttribute("colspan",colSpanCount);
					cell.setAttribute("colSpan",colSpanCount); // Needed for IE
					colSpanCount = 1;
				}
				config.formatterHelpers.applyCssHelper(cell,styles);
				w.subWikifyTerm(cell,this.cellTermRegExp);
				if(w.matchText.substr(w.matchText.length-2,1) == " ") // spaceRight
					cell.align = spaceLeft ? "center" : "left";
				else if(spaceLeft)
					cell.align = "right";
				w.nextMatch--;
			}
			col++;
			this.cellRegExp.lastIndex = w.nextMatch;
			cellMatch = this.cellRegExp.exec(w.source);
		}
	}
},

{
	name: "heading",
	match: "^!{1,6}",
	termRegExp: /(\n)/mg,
	handler: function(w)
	{
		w.subWikifyTerm(createTiddlyElement(w.output,"h" + w.matchLength),this.termRegExp);
	}
},

{
	name: "list",
	match: "^(?:[\\*#;:]+)",
	lookaheadRegExp: /^(?:(?:(\*)|(#)|(;)|(:))+)/mg,
	termRegExp: /(\n)/mg,
	handler: function(w)
	{
		var stack = [w.output];
		var currLevel = 0, currType = null;
		var listLevel, listType, itemType, baseType;
		w.nextMatch = w.matchStart;
		this.lookaheadRegExp.lastIndex = w.nextMatch;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) {
			if(lookaheadMatch[1]) {
				listType = "ul";
				itemType = "li";
			} else if(lookaheadMatch[2]) {
				listType = "ol";
				itemType = "li";
			} else if(lookaheadMatch[3]) {
				listType = "dl";
				itemType = "dt";
			} else if(lookaheadMatch[4]) {
				listType = "dl";
				itemType = "dd";
			}
			if(!baseType)
				baseType = listType;
			listLevel = lookaheadMatch[0].length;
			w.nextMatch += lookaheadMatch[0].length;
			var t;
			if(listLevel > currLevel) {
				for(t=currLevel; t<listLevel; t++) {
					var target = (currLevel == 0) ? stack[stack.length-1] : stack[stack.length-1].lastChild;
					stack.push(createTiddlyElement(target,listType));
				}
			} else if(listType!=baseType && listLevel==1) {
				w.nextMatch -= lookaheadMatch[0].length;
				return;
			} else if(listLevel < currLevel) {
				for(t=currLevel; t>listLevel; t--)
					stack.pop();
			} else if(listLevel == currLevel && listType != currType) {
				stack.pop();
				stack.push(createTiddlyElement(stack[stack.length-1].lastChild,listType));
			}
			currLevel = listLevel;
			currType = listType;
			var e = createTiddlyElement(stack[stack.length-1],itemType);
			w.subWikifyTerm(e,this.termRegExp);
			this.lookaheadRegExp.lastIndex = w.nextMatch;
			lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		}
	}
},

{
	name: "quoteByBlock",
	match: "^<<<\\n",
	termRegExp: /(^<<<(\n|$))/mg,
	element: "blockquote",
	handler: config.formatterHelpers.createElementAndWikify
},

{
	name: "quoteByLine",
	match: "^>+",
	lookaheadRegExp: /^>+/mg,
	termRegExp: /(\n)/mg,
	element: "blockquote",
	handler: function(w)
	{
		var stack = [w.output];
		var currLevel = 0;
		var newLevel = w.matchLength;
		var t;
		do {
			if(newLevel > currLevel) {
				for(t=currLevel; t<newLevel; t++)
					stack.push(createTiddlyElement(stack[stack.length-1],this.element));
			} else if(newLevel < currLevel) {
				for(t=currLevel; t>newLevel; t--)
					stack.pop();
			}
			currLevel = newLevel;
			w.subWikifyTerm(stack[stack.length-1],this.termRegExp);
			createTiddlyElement(stack[stack.length-1],"br");
			this.lookaheadRegExp.lastIndex = w.nextMatch;
			var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
			var matched = lookaheadMatch && lookaheadMatch.index == w.nextMatch;
			if(matched) {
				newLevel = lookaheadMatch[0].length;
				w.nextMatch += lookaheadMatch[0].length;
			}
		} while(matched);
	}
},

{
	name: "rule",
	match: "^----+$\\n?|<hr ?/?>\\n?",
	handler: function(w)
	{
		createTiddlyElement(w.output,"hr");
	}
},

{
	name: "monospacedByLine",
	match: "^(?:/\\*\\{\\{\\{\\*/|\\{\\{\\{|//\\{\\{\\{|<!--\\{\\{\\{-->)\\n",
	element: "pre",
	handler: function(w)
	{
		switch(w.matchText) {
		case "/*{{{*/\n": // CSS
			this.lookaheadRegExp = /\/\*\{\{\{\*\/\n*((?:^[^\n]*\n)+?)(\n*^\/\*\}\}\}\*\/$\n?)/mg;
			break;
		case "{{{\n": // monospaced block
			this.lookaheadRegExp = /^\{\{\{\n((?:^[^\n]*\n)+?)(^\}\}\}$\n?)/mg;
			break;
		case "//{{{\n": // plugin
			this.lookaheadRegExp = /^\/\/\{\{\{\n\n*((?:^[^\n]*\n)+?)(\n*^\/\/\}\}\}$\n?)/mg;
			break;
		case "<!--{{{-->\n": //template
			this.lookaheadRegExp = /<!--\{\{\{-->\n*((?:^[^\n]*\n)+?)(\n*^<!--\}\}\}-->$\n?)/mg;
			break;
		default:
			break;
		}
		config.formatterHelpers.enclosedTextHelper.call(this,w);
	}
},

{
	name: "wikifyComment",
	match: "^(?:/\\*\\*\\*|<!---)\\n",
	handler: function(w)
	{
		var termRegExp = (w.matchText == "/***\n") ? (/(^\*\*\*\/\n)/mg) : (/(^--->\n)/mg);
		w.subWikifyTerm(w.output,termRegExp);
	}
},

{
	name: "macro",
	match: "<<",
	lookaheadRegExp: /<<([^>\s]+)(?:\s*)((?:[^>]|(?:>(?!>)))*)>>/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart && lookaheadMatch[1]) {
			w.nextMatch = this.lookaheadRegExp.lastIndex;
			invokeMacro(w.output,lookaheadMatch[1],lookaheadMatch[2],w,w.tiddler);
		}
	}
},

{
	name: "prettyLink",
	match: "\\[\\[",
	lookaheadRegExp: /\[\[(.*?)(?:\|(~)?(.*?))?\]\]/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var e;
			var text = lookaheadMatch[1];
			if(lookaheadMatch[3]) {
				// Pretty bracketted link
				var link = lookaheadMatch[3];
				e = (!lookaheadMatch[2] && config.formatterHelpers.isExternalLink(link)) ?
						createExternalLink(w.output,link) : createTiddlyLink(w.output,decodeURIComponent(link),false,null,w.isStatic,w.tiddler);
			} else {
				// Simple bracketted link
				e = createTiddlyLink(w.output,decodeURIComponent(text),false,null,w.isStatic,w.tiddler);
			}
			createTiddlyText(e,text);
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
},

{
	name: "wikiLink",
	match: config.textPrimitives.unWikiLink+"?"+config.textPrimitives.wikiLink,
	handler: function(w)
	{
		if(w.matchText.substr(0,1) == config.textPrimitives.unWikiLink) {
			w.outputText(w.output,w.matchStart+1,w.nextMatch);
			return;
		}
		if(w.matchStart > 0) {
			var preRegExp = new RegExp(config.textPrimitives.anyLetterStrict,"mg");
			preRegExp.lastIndex = w.matchStart-1;
			var preMatch = preRegExp.exec(w.source);
			if(preMatch.index == w.matchStart-1) {
				w.outputText(w.output,w.matchStart,w.nextMatch);
				return;
			}
		}
		if(w.autoLinkWikiWords || store.isShadowTiddler(w.matchText)) {
			var link = createTiddlyLink(w.output,w.matchText,false,null,w.isStatic,w.tiddler);
			w.outputText(link,w.matchStart,w.nextMatch);
		} else {
			w.outputText(w.output,w.matchStart,w.nextMatch);
		}
	}
},

{
	name: "urlLink",
	match: config.textPrimitives.urlPattern,
	handler: function(w)
	{
		w.outputText(createExternalLink(w.output,w.matchText),w.matchStart,w.nextMatch);
	}
},

{
	name: "image",
	match: "\\[[<>]?[Ii][Mm][Gg]\\[",
	lookaheadRegExp: /\[([<]?)(>?)[Ii][Mm][Gg]\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var e = w.output;
			if(lookaheadMatch[5]) {
				var link = lookaheadMatch[5];
				e = config.formatterHelpers.isExternalLink(link) ? createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic,w.tiddler);
				addClass(e,"imageLink");
			}
			var img = createTiddlyElement(e,"img");
			if(lookaheadMatch[1])
				img.align = "left";
			else if(lookaheadMatch[2])
				img.align = "right";
			if(lookaheadMatch[3]) {
				img.title = lookaheadMatch[3];
				img.setAttribute("alt",lookaheadMatch[3]);
			}
			img.src = lookaheadMatch[4];
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
},

{
	name: "html",
	match: "<[Hh][Tt][Mm][Ll]>",
	lookaheadRegExp: /<[Hh][Tt][Mm][Ll]>((?:.|\n)*?)<\/[Hh][Tt][Mm][Ll]>/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			createTiddlyElement(w.output,"span").innerHTML = lookaheadMatch[1];
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
},

{
	name: "commentByBlock",
	match: "/%",
	lookaheadRegExp: /\/%((?:.|\n)*?)%\//mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
			w.nextMatch = this.lookaheadRegExp.lastIndex;
	}
},

{
	name: "characterFormat",
	match: "''|//|__|\\^\\^|~~|--(?!\\s|$)|\\{\\{\\{",
	handler: function(w)
	{
		switch(w.matchText) {
		case "''":
			w.subWikifyTerm(w.output.appendChild(document.createElement("strong")),/('')/mg);
			break;
		case "//":
			w.subWikifyTerm(createTiddlyElement(w.output,"em"),/(\/\/)/mg);
			break;
		case "__":
			w.subWikifyTerm(createTiddlyElement(w.output,"u"),/(__)/mg);
			break;
		case "^^":
			w.subWikifyTerm(createTiddlyElement(w.output,"sup"),/(\^\^)/mg);
			break;
		case "~~":
			w.subWikifyTerm(createTiddlyElement(w.output,"sub"),/(~~)/mg);
			break;
		case "--":
			w.subWikifyTerm(createTiddlyElement(w.output,"strike"),/(--)/mg);
			break;
		case "{{{":
			var lookaheadRegExp = /\{\{\{((?:.|\n)*?)\}\}\}/mg;
			lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = lookaheadRegExp.exec(w.source);
			if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
				createTiddlyElement(w.output,"code",null,null,lookaheadMatch[1]);
				w.nextMatch = lookaheadRegExp.lastIndex;
			}
			break;
		}
	}
},

{
	name: "customFormat",
	match: "@@|\\{\\{",
	handler: function(w)
	{
		switch(w.matchText) {
		case "@@":
			var e = createTiddlyElement(w.output,"span");
			var styles = config.formatterHelpers.inlineCssHelper(w);
			if(styles.length == 0)
				e.className = "marked";
			else
				config.formatterHelpers.applyCssHelper(e,styles);
			w.subWikifyTerm(e,/(@@)/mg);
			break;
		case "{{":
			var lookaheadRegExp = /\{\{[\s]*([\w]+[\s\w]*)[\s]*\{(\n?)/mg;
			lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = lookaheadRegExp.exec(w.source);
			if(lookaheadMatch) {
				w.nextMatch = lookaheadRegExp.lastIndex;
				e = createTiddlyElement(w.output,lookaheadMatch[2] == "\n" ? "div" : "span",null,lookaheadMatch[1]);
				w.subWikifyTerm(e,/(\}\}\})/mg);
			}
			break;
		}
	}
},

{
	name: "mdash",
	match: "--",
	handler: function(w)
	{
		createTiddlyElement(w.output,"span").innerHTML = "&mdash;";
	}
},

{
	name: "lineBreak",
	match: "\\n|<br ?/?>",
	handler: function(w)
	{
		createTiddlyElement(w.output,"br");
	}
},

{
	name: "rawText",
	match: "\"{3}|<nowiki>",
	lookaheadRegExp: /(?:\"{3}|<nowiki>)((?:.|\n)*?)(?:\"{3}|<\/nowiki>)/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			createTiddlyElement(w.output,"span",null,null,lookaheadMatch[1]);
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
},

{
	name: "htmlEntitiesEncoding",
	match: "(?:(?:&#?[a-zA-Z0-9]{2,8};|.)(?:&#?(?:x0*(?:3[0-6][0-9a-fA-F]|1D[c-fC-F][0-9a-fA-F]|20[d-fD-F][0-9a-fA-F]|FE2[0-9a-fA-F])|0*(?:76[89]|7[7-9][0-9]|8[0-7][0-9]|761[6-9]|76[2-7][0-9]|84[0-3][0-9]|844[0-7]|6505[6-9]|6506[0-9]|6507[0-1]));)+|&#?[a-zA-Z0-9]{2,8};)",
	handler: function(w)
	{
		createTiddlyElement(w.output,"span").innerHTML = w.matchText;
	}
}

];

//--
//-- Wikifier
//--

function getParser(tiddler,format)
{
	if(tiddler) {
		if(!format)
			format = tiddler.fields["wikiformat"];
		var i;
		if(format) {
			for(i in config.parsers) {
				if(format == config.parsers[i].format)
					return config.parsers[i];
			}
		} else {
			for(i in config.parsers) {
				if(tiddler.isTagged(config.parsers[i].formatTag))
					return config.parsers[i];
			}
		}
	}
	return formatter;
}

function wikify(source,output,highlightRegExp,tiddler)
{
	if(source) {
		var wikifier = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler);
		var t0 = new Date();
		wikifier.subWikify(output);
		if(tiddler && config.options.chkDisplayInstrumentation)
			displayMessage("wikify:" +tiddler.title+ " in " + (new Date()-t0) + " ms");
	}
}

function wikifyStatic(source,highlightRegExp,tiddler,format)
{
	var e = createTiddlyElement(document.body,"pre");
	e.style.display = "none";
	var html = "";
	if(source && source != "") {
		if(!tiddler)
			tiddler = new Tiddler("temp");
		var wikifier = new Wikifier(source,getParser(tiddler,format),highlightRegExp,tiddler);
		wikifier.isStatic = true;
		wikifier.subWikify(e);
		html = e.innerHTML;
		removeNode(e);
	}
	return html;
}

function wikifyPlain(title,theStore,limit)
{
	if(!theStore)
		theStore = store;
	if(theStore.tiddlerExists(title) || theStore.isShadowTiddler(title)) {
		return wikifyPlainText(theStore.getTiddlerText(title),limit,tiddler);
	} else {
		return "";
	}
}

function wikifyPlainText(text,limit,tiddler)
{
	if(limit > 0)
		text = text.substr(0,limit);
	var wikifier = new Wikifier(text,formatter,null,tiddler);
	return wikifier.wikifyPlain();
}

function highlightify(source,output,highlightRegExp,tiddler)
{
	if(source) {
		var wikifier = new Wikifier(source,formatter,highlightRegExp,tiddler);
		wikifier.outputText(output,0,source.length);
	}
}

function Wikifier(source,formatter,highlightRegExp,tiddler)
{
	this.source = source;
	this.output = null;
	this.formatter = formatter;
	this.nextMatch = 0;
	this.autoLinkWikiWords = tiddler && tiddler.autoLinkWikiWords() == false ? false : true;
	this.highlightRegExp = highlightRegExp;
	this.highlightMatch = null;
	this.isStatic = false;
	if(highlightRegExp) {
		highlightRegExp.lastIndex = 0;
		this.highlightMatch = highlightRegExp.exec(source);
	}
	this.tiddler = tiddler;
}

Wikifier.prototype.wikifyPlain = function()
{
	var e = createTiddlyElement(document.body,"div");
	e.style.display = "none";
	this.subWikify(e);
	var text = getPlainText(e);
	removeNode(e);
	return text;
};

Wikifier.prototype.subWikify = function(output,terminator)
{
	try {
		if(terminator)
			this.subWikifyTerm(output,new RegExp("(" + terminator + ")","mg"));
		else
			this.subWikifyUnterm(output);
	} catch(ex) {
		showException(ex);
	}
};

Wikifier.prototype.subWikifyUnterm = function(output)
{
	var oldOutput = this.output;
	this.output = output;
	this.formatter.formatterRegExp.lastIndex = this.nextMatch;
	var formatterMatch = this.formatter.formatterRegExp.exec(this.source);
	while(formatterMatch) {
		// Output any text before the match
		if(formatterMatch.index > this.nextMatch)
			this.outputText(this.output,this.nextMatch,formatterMatch.index);
		// Set the match parameters for the handler
		this.matchStart = formatterMatch.index;
		this.matchLength = formatterMatch[0].length;
		this.matchText = formatterMatch[0];
		this.nextMatch = this.formatter.formatterRegExp.lastIndex;
		for(var t=1; t<formatterMatch.length; t++) {
			if(formatterMatch[t]) {
				this.formatter.formatters[t-1].handler(this);
				this.formatter.formatterRegExp.lastIndex = this.nextMatch;
				break;
			}
		}
		formatterMatch = this.formatter.formatterRegExp.exec(this.source);
	}
	if(this.nextMatch < this.source.length) {
		this.outputText(this.output,this.nextMatch,this.source.length);
		this.nextMatch = this.source.length;
	}
	this.output = oldOutput;
};

Wikifier.prototype.subWikifyTerm = function(output,terminatorRegExp)
{
	var oldOutput = this.output;
	this.output = output;
	terminatorRegExp.lastIndex = this.nextMatch;
	var terminatorMatch = terminatorRegExp.exec(this.source);
	this.formatter.formatterRegExp.lastIndex = this.nextMatch;
	var formatterMatch = this.formatter.formatterRegExp.exec(terminatorMatch ? this.source.substr(0,terminatorMatch.index) : this.source);
	while(terminatorMatch || formatterMatch) {
		if(terminatorMatch && (!formatterMatch || terminatorMatch.index <= formatterMatch.index)) {
			if(terminatorMatch.index > this.nextMatch)
				this.outputText(this.output,this.nextMatch,terminatorMatch.index);
			this.matchText = terminatorMatch[1];
			this.matchLength = terminatorMatch[1].length;
			this.matchStart = terminatorMatch.index;
			this.nextMatch = this.matchStart + this.matchLength;
			this.output = oldOutput;
			return;
		}
		if(formatterMatch.index > this.nextMatch)
			this.outputText(this.output,this.nextMatch,formatterMatch.index);
		this.matchStart = formatterMatch.index;
		this.matchLength = formatterMatch[0].length;
		this.matchText = formatterMatch[0];
		this.nextMatch = this.formatter.formatterRegExp.lastIndex;
		for(var t=1; t<formatterMatch.length; t++) {
			if(formatterMatch[t]) {
				this.formatter.formatters[t-1].handler(this);
				this.formatter.formatterRegExp.lastIndex = this.nextMatch;
				break;
			}
		}
		terminatorRegExp.lastIndex = this.nextMatch;
		terminatorMatch = terminatorRegExp.exec(this.source);
		formatterMatch = this.formatter.formatterRegExp.exec(terminatorMatch ? this.source.substr(0,terminatorMatch.index) : this.source);
	}
	if(this.nextMatch < this.source.length) {
		this.outputText(this.output,this.nextMatch,this.source.length);
		this.nextMatch = this.source.length;
	}
	this.output = oldOutput;
};

Wikifier.prototype.outputText = function(place,startPos,endPos)
{
	while(this.highlightMatch && (this.highlightRegExp.lastIndex > startPos) && (this.highlightMatch.index < endPos) && (startPos < endPos)) {
		if(this.highlightMatch.index > startPos) {
			createTiddlyText(place,this.source.substring(startPos,this.highlightMatch.index));
			startPos = this.highlightMatch.index;
		}
		var highlightEnd = Math.min(this.highlightRegExp.lastIndex,endPos);
		var theHighlight = createTiddlyElement(place,"span",null,"highlight",this.source.substring(startPos,highlightEnd));
		startPos = highlightEnd;
		if(startPos >= this.highlightRegExp.lastIndex)
			this.highlightMatch = this.highlightRegExp.exec(this.source);
	}
	if(startPos < endPos) {
		createTiddlyText(place,this.source.substring(startPos,endPos));
	}
};

//--
//-- Macro definitions
//--

config.macros.today.handler = function(place,macroName,params)
{
	var now = new Date();
	var text = params[0] ? now.formatString(params[0].trim()) : now.toLocaleString();
	jQuery("<span/>").text(text).appendTo(place);
};

config.macros.version.handler = function(place)
{
	jQuery("<span/>").text(formatVersion()).appendTo(place);
};

config.macros.list.handler = function(place,macroName,params)
{
	var type = params[0] || "all";
	var list = document.createElement("ul");
	place.appendChild(list);
	if(this[type].prompt)
		createTiddlyElement(list,"li",null,"listTitle",this[type].prompt);
	var results;
	if(this[type].handler)
		results = this[type].handler(params);
	for(var t = 0; t < results.length; t++) {
		var li = document.createElement("li");
		list.appendChild(li);
		createTiddlyLink(li,typeof results[t] == "string" ? results[t] : results[t].title,true);
	}
};

config.macros.list.all.handler = function(params)
{
	return store.reverseLookup("tags","excludeLists",false,"title");
};

config.macros.list.missing.handler = function(params)
{
	return store.getMissingLinks();
};

config.macros.list.orphans.handler = function(params)
{
	return store.getOrphans();
};

config.macros.list.shadowed.handler = function(params)
{
	return store.getShadowed();
};

config.macros.list.touched.handler = function(params)
{
	return store.getTouched();
};

config.macros.list.filter.handler = function(params)
{
	var filter = params[1];
	var results = [];
	if(filter) {
		var tiddlers = store.filterTiddlers(filter);
		for(var t=0; t<tiddlers.length; t++)
			results.push(tiddlers[t].title);
	}
	return results;
};

config.macros.allTags.handler = function(place,macroName,params)
{
	var tags = store.getTags(params[0]);
	var ul = createTiddlyElement(place,"ul");
	if(tags.length == 0)
		createTiddlyElement(ul,"li",null,"listTitle",this.noTags);
	for(var t=0; t<tags.length; t++) {
		var title = tags[t][0];
		var info = getTiddlyLinkInfo(title);
		var li = createTiddlyElement(ul,"li");
		var btn = createTiddlyButton(li,title + " (" + tags[t][1] + ")",this.tooltip.format([title]),onClickTag,info.classes);
		btn.setAttribute("tag",title);
		btn.setAttribute("refresh","link");
		btn.setAttribute("tiddlyLink",title);
	}
};

config.macros.timeline.handler = function(place,macroName,params)
{
	var field = params[0] || "modified";
	var tiddlers = store.reverseLookup("tags","excludeLists",false,field);
	var lastDay = "";
	var last = params[1] ? tiddlers.length-Math.min(tiddlers.length,parseInt(params[1])) : 0;
	var dateFormat = params[2] || this.dateFormat;
	for(var t=tiddlers.length-1; t>=last; t--) {
		var tiddler = tiddlers[t];
		var theDay = tiddler[field].convertToLocalYYYYMMDDHHMM().substr(0,8);
		if(theDay != lastDay) {
			var ul = document.createElement("ul");
			place.appendChild(ul);
			createTiddlyElement(ul,"li",null,"listTitle",tiddler[field].formatString(dateFormat));
			lastDay = theDay;
		}
		createTiddlyElement(ul,"li",null,"listLink").appendChild(createTiddlyLink(place,tiddler.title,true));
	}
};

config.macros.tiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	params = paramString.parseParams("name",null,true,false,true);
	var names = params[0]["name"];
	var tiddlerName = names[0];
	var className = names[1] || null;
	var args = params[0]["with"];
	var wrapper = createTiddlyElement(place,"span",null,className);
	if(!args) {
		wrapper.setAttribute("refresh","content");
		wrapper.setAttribute("tiddler",tiddlerName);
	}
	var text = store.getTiddlerText(tiddlerName);
	if(text) {
		var stack = config.macros.tiddler.tiddlerStack;
		if(stack.indexOf(tiddlerName) !== -1)
			return;
		stack.push(tiddlerName);
		try {
			var n = args ? Math.min(args.length,9) : 0;
			for(var i=0; i<n; i++) {
				var placeholderRE = new RegExp("\\$" + (i + 1),"mg");
				text = text.replace(placeholderRE,args[i]);
			}
			config.macros.tiddler.renderText(wrapper,text,tiddlerName,params);
		} finally {
			stack.pop();
		}
	}
};

config.macros.tiddler.renderText = function(place,text,tiddlerName,params)
{
	wikify(text,place,null,store.getTiddler(tiddlerName));
};

config.macros.tiddler.tiddlerStack = [];

config.macros.tag.handler = function(place,macroName,params)
{
	createTagButton(place,params[0],null,params[1],params[2]);
};

config.macros.tags.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	params = paramString.parseParams("anon",null,true,false,false);
	var ul = createTiddlyElement(place,"ul");
	var title = getParam(params,"anon","");
	if(title && store.tiddlerExists(title))
		tiddler = store.getTiddler(title);
	var sep = getParam(params,"sep"," ");
	var lingo = config.views.wikified.tag;
	var prompt = tiddler.tags.length == 0 ? lingo.labelNoTags : lingo.labelTags;
	createTiddlyElement(ul,"li",null,"listTitle",prompt.format([tiddler.title]));
	for(var t=0; t<tiddler.tags.length; t++) {
		var tag = store.getTiddler(tiddler.tags[t]); 
		if(!tag || !tag.tags.contains("excludeLists")) { 
			createTagButton(createTiddlyElement(ul,"li"),tiddler.tags[t],tiddler.title);
			if(t<tiddler.tags.length-1)
				createTiddlyText(ul,sep);
		}
	}
};

config.macros.tagging.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	params = paramString.parseParams("anon",null,true,false,false);
	var ul = createTiddlyElement(place,"ul");
	var title = getParam(params,"anon","");
	if(title == "" && tiddler instanceof Tiddler)
		title = tiddler.title;
	var sep = getParam(params,"sep"," ");
	ul.setAttribute("title",this.tooltip.format([title]));
	var tagged = store.getTaggedTiddlers(title);
	var prompt = tagged.length == 0 ? this.labelNotTag : this.label;
	createTiddlyElement(ul,"li",null,"listTitle",prompt.format([title,tagged.length]));
	for(var t=0; t<tagged.length; t++) {
		createTiddlyLink(createTiddlyElement(ul,"li"),tagged[t].title,true);
		if(t<tagged.length-1)
			createTiddlyText(ul,sep);
	}
};

config.macros.closeAll.handler = function(place)
{
	createTiddlyButton(place,this.label,this.prompt,this.onClick);
};

config.macros.closeAll.onClick = function(e)
{
	story.closeAllTiddlers();
	return false;
};

config.macros.permaview.handler = function(place)
{
	createTiddlyButton(place,this.label,this.prompt,this.onClick);
};

config.macros.permaview.onClick = function(e)
{
	story.permaView();
	return false;
};

config.macros.saveChanges.handler = function(place,macroName,params)
{
	if(!readOnly)
		createTiddlyButton(place,params[0] || this.label,params[1] || this.prompt,this.onClick,null,null,this.accessKey);
};

config.macros.saveChanges.onClick = function(e)
{
	saveChanges();
	return false;
};

config.macros.slider.onClickSlider = function(ev)
{
	var e = ev || window.event;
	var n = this.nextSibling;
	var cookie = n.getAttribute("cookie");
	var isOpen = n.style.display != "none";
	if(config.options.chkAnimate && anim && typeof Slider == "function")
		anim.startAnimating(new Slider(n,!isOpen,null,"none"));
	else
		n.style.display = isOpen ? "none" : "block";
	config.options[cookie] = !isOpen;
	saveOptionCookie(cookie);
	return false;
};

config.macros.slider.createSlider = function(place,cookie,title,tooltip)
{
	var c = cookie || "";
	var btn = createTiddlyButton(place,title,tooltip,this.onClickSlider);
	var panel = createTiddlyElement(null,"div",null,"sliderPanel");
	panel.setAttribute("cookie",c);
	panel.style.display = config.options[c] ? "block" : "none";
	place.appendChild(panel);
	return panel;
};

config.macros.slider.handler = function(place,macroName,params)
{
	var panel = this.createSlider(place,params[0],params[2],params[3]);
	var text = store.getTiddlerText(params[1]);
	panel.setAttribute("refresh","content");
	panel.setAttribute("tiddler",params[1]);
	if(text)
		wikify(text,panel,null,store.getTiddler(params[1]));
};

// <<gradient [[tiddler name]] vert|horiz rgb rgb rgb rgb... >>
config.macros.gradient.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	var panel = wikifier ? createTiddlyElement(place,"div",null,"gradient") : place;
	panel.style.position = "relative";
	panel.style.overflow = "hidden";
	panel.style.zIndex = "0";
	if(wikifier) {
		var styles = config.formatterHelpers.inlineCssHelper(wikifier);
		config.formatterHelpers.applyCssHelper(panel,styles);
	}
	params = paramString.parseParams("color");
	var locolors = [], hicolors = [];
	for(var t=2; t<params.length; t++) {
		var c = params[t].value;
		if(params[t].name == "snap") {
			hicolors[hicolors.length-1] = c;
		} else {
			locolors.push(c);
			hicolors.push(c);
		}
	}
	drawGradient(panel,params[1].value != "vert",locolors,hicolors);
	if(wikifier)
		wikifier.subWikify(panel,">>");
	if(document.all) {
		panel.style.height = "100%";
		panel.style.width = "100%";
	}
};

config.macros.message.handler = function(place,macroName,params)
{
	if(params[0]) {
		var names = params[0].split(".");
		var lookupMessage = function(root,nameIndex) {
				if(names[nameIndex] in root) {
					if(nameIndex < names.length-1)
						return (lookupMessage(root[names[nameIndex]],nameIndex+1));
					else
						return root[names[nameIndex]];
				} else
					return null;
			};
		var m = lookupMessage(config,0);
		if(m == null)
			m = lookupMessage(window,0);
		createTiddlyText(place,m.toString().format(params.splice(1)));
	}
};


config.macros.view.views = {
	text: function(value,place,params,wikifier,paramString,tiddler) {
		highlightify(value,place,highlightHack,tiddler);
	},
	link: function(value,place,params,wikifier,paramString,tiddler) {
		createTiddlyLink(place,value,true);
	},
	wikified: function(value,place,params,wikifier,paramString,tiddler) {
		if(params[2])
			value=params[2].unescapeLineBreaks().format([value]);
		wikify(value,place,highlightHack,tiddler);
	},
	date: function(value,place,params,wikifier,paramString,tiddler) {
		value = Date.convertFromYYYYMMDDHHMM(value);
		createTiddlyText(place,value.formatString(params[2] ? params[2] : config.views.wikified.dateFormat));
	}
};

config.macros.view.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	if((tiddler instanceof Tiddler) && params[0]) {
		var value = store.getValue(tiddler,params[0]);
		if(value) {
			var type = params[1] || config.macros.view.defaultView;
			var handler = config.macros.view.views[type];
			if(handler)
				handler(value,place,params,wikifier,paramString,tiddler);
		}
	}
};

config.macros.edit.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	var field = params[0];
	var rows = params[1] || 0;
	var defVal = params[2] || '';
	if((tiddler instanceof Tiddler) && field) {
		story.setDirty(tiddler.title,true);
		var e,v;
		if(field != "text" && !rows) {
			e = createTiddlyElement(null,"input");
			if(tiddler.isReadOnly())
				e.setAttribute("readOnly","readOnly");
			e.setAttribute("edit",field);
			e.setAttribute("type","text");
			e.value = store.getValue(tiddler,field) || defVal;
			e.setAttribute("size","40");
			e.setAttribute("autocomplete","off");
			place.appendChild(e);
		} else {
			var wrapper1 = createTiddlyElement(null,"fieldset",null,"fieldsetFix");
			var wrapper2 = createTiddlyElement(wrapper1,"div");
			e = createTiddlyElement(wrapper2,"textarea");
			if(tiddler.isReadOnly())
				e.setAttribute("readOnly","readOnly");
			e.value = v = store.getValue(tiddler,field) || defVal;
			rows = rows || 10;
			var lines = v.match(/\n/mg);
			var maxLines = Math.max(parseInt(config.options.txtMaxEditRows),5);
			if(lines != null && lines.length > rows)
				rows = lines.length + 5;
			rows = Math.min(rows,maxLines);
			e.setAttribute("rows",rows);
			e.setAttribute("edit",field);
			place.appendChild(wrapper1);
		}
		return e;
	}
};

config.macros.tagChooser.onClick = function(ev)
{
	var e = ev || window.event;
	var lingo = config.views.editor.tagChooser;
	var popup = Popup.create(this);
	var tags = store.getTags(this.getAttribute("tags"));
	if(tags.length == 0)
		jQuery("<li/>").text(lingo.popupNone).appendTo(jQuery(popup));
	for(var t=0; t<tags.length; t++) {
		var tag = createTiddlyButton(createTiddlyElement(popup,"li"),tags[t][0],lingo.tagTooltip.format([tags[t][0]]),config.macros.tagChooser.onTagClick);
		tag.setAttribute("tag",tags[t][0]);
		tag.setAttribute("tiddler",this.getAttribute("tiddler"));
	}
	Popup.show();
	e.cancelBubble = true;
	if(e.stopPropagation) e.stopPropagation();
	return false;
};

config.macros.tagChooser.onTagClick = function(ev)
{
	var e = ev || window.event;
	if(e.metaKey || e.ctrlKey) stopEvent(e); //# keep popup open on CTRL-click
	var tag = this.getAttribute("tag");
	var title = this.getAttribute("tiddler");
	if(!readOnly)
		story.setTiddlerTag(title,tag,0);
	return false;
};

config.macros.tagChooser.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	if(tiddler instanceof Tiddler) {
		var lingo = config.views.editor.tagChooser;
		var btn = createTiddlyButton(place,lingo.text,lingo.tooltip,this.onClick);
		btn.setAttribute("tiddler",tiddler.title);
		btn.setAttribute("tags",params[0]);
	}
};

config.macros.refreshDisplay.handler = function(place)
{
	createTiddlyButton(place,this.label,this.prompt,this.onClick);
};

config.macros.refreshDisplay.onClick = function(e)
{
	refreshAll();
	return false;
};

config.macros.annotations.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	var title = tiddler ? tiddler.title : null;
	var a = title ? config.annotations[title] : null;
	if(!tiddler || !title || !a)
		return;
	var text = a.format([title]);
	wikify(text,createTiddlyElement(place,"div",null,"annotation"),null,tiddler);
};

//--
//-- NewTiddler and NewJournal macros
//--

config.macros.newTiddler.createNewTiddlerButton = function(place,title,params,label,prompt,accessKey,newFocus,isJournal)
{
	var tags = [];
	for(var t=1; t<params.length; t++) {
		if((params[t].name == "anon" && t != 1) || (params[t].name == "tag"))
			tags.push(params[t].value);
	}
	label = getParam(params,"label",label);
	prompt = getParam(params,"prompt",prompt);
	accessKey = getParam(params,"accessKey",accessKey);
	newFocus = getParam(params,"focus",newFocus);
	var customFields = getParam(params,"fields","");
	if(!customFields && !store.isShadowTiddler(title))
		customFields = String.encodeHashMap(config.defaultCustomFields);
	var btn = createTiddlyButton(place,label,prompt,this.onClickNewTiddler,null,null,accessKey);
	btn.setAttribute("newTitle",title);
	btn.setAttribute("isJournal",isJournal ? "true" : "false");
	if(tags.length > 0)
		btn.setAttribute("params",tags.join("|"));
	btn.setAttribute("newFocus",newFocus);
	btn.setAttribute("newTemplate",getParam(params,"template",DEFAULT_EDIT_TEMPLATE));
	if(customFields !== "")
		btn.setAttribute("customFields",customFields);
	var text = getParam(params,"text");
	if(text !== undefined)
		btn.setAttribute("newText",text);
	return btn;
};

config.macros.newTiddler.onClickNewTiddler = function()
{
	var title = this.getAttribute("newTitle");
	if(this.getAttribute("isJournal") == "true") {
		title = new Date().formatString(title.trim());
	}
	var params = this.getAttribute("params");
	var tags = params ? params.split("|") : [];
	var focus = this.getAttribute("newFocus");
	var template = this.getAttribute("newTemplate");
	var customFields = this.getAttribute("customFields");
	if(!customFields && !store.isShadowTiddler(title))
		customFields = String.encodeHashMap(config.defaultCustomFields);
	story.displayTiddler(null,title,template,false,null,null);
	var tiddlerElem = story.getTiddler(title);
	if(customFields)
		story.addCustomFields(tiddlerElem,customFields);
	var text = this.getAttribute("newText");
	if(typeof text == "string" && story.getTiddlerField(title,"text"))
		story.getTiddlerField(title,"text").value = text.format([title]);
	for(var t=0;t<tags.length;t++)
		story.setTiddlerTag(title,tags[t],+1);
	story.focusTiddler(title,focus);
	return false;
};

config.macros.newTiddler.handler = function(place,macroName,params,wikifier,paramString)
{
	if(!readOnly) {
		params = paramString.parseParams("anon",null,true,false,false);
		var title = params[1] && params[1].name == "anon" ? params[1].value : this.title;
		title = getParam(params,"title",title);
		this.createNewTiddlerButton(place,title,params,this.label,this.prompt,this.accessKey,"title",false);
	}
};

config.macros.newJournal.handler = function(place,macroName,params,wikifier,paramString)
{
	if(!readOnly) {
		params = paramString.parseParams("anon",null,true,false,false);
		var title = params[1] && params[1].name == "anon" ? params[1].value : config.macros.timeline.dateFormat;
		title = getParam(params,"title",title);
		config.macros.newTiddler.createNewTiddlerButton(place,title,params,this.label,this.prompt,this.accessKey,"text",true);
	}
};

//--
//-- Search macro
//--

config.macros.search.handler = function(place,macroName,params)
{
	var searchTimeout = null;
	var btn = createTiddlyButton(place,this.label,this.prompt,this.onClick,"searchButton");
	var txt = createTiddlyElement(null,"input",null,"txtOptionInput searchField");
	if(params[0])
		txt.value = params[0];
	if(config.browser.isSafari) {
		txt.setAttribute("type","search");
		txt.setAttribute("results","5");
	} else {
		txt.setAttribute("type","text");
	}
	place.appendChild(txt);
	txt.onkeyup = this.onKeyPress;
	txt.onfocus = this.onFocus;
	txt.setAttribute("size",this.sizeTextbox);
	txt.setAttribute("accessKey",params[1] || this.accessKey);
	txt.setAttribute("autocomplete","off");
	txt.setAttribute("lastSearchText","");
};

// Global because there's only ever one outstanding incremental search timer
config.macros.search.timeout = null;

config.macros.search.doSearch = function(txt)
{
	if(txt.value.length > 0) {
		story.search(txt.value,config.options.chkCaseSensitiveSearch,config.options.chkRegExpSearch);
		txt.setAttribute("lastSearchText",txt.value);
	}
};

config.macros.search.onClick = function(e)
{
	config.macros.search.doSearch(this.nextSibling);
	return false;
};

config.macros.search.onKeyPress = function(ev)
{
	var e = ev || window.event;
	switch(e.keyCode) {
		case 13: // Ctrl-Enter
		case 10: // Ctrl-Enter on IE PC
			config.macros.search.doSearch(this);
			break;
		case 27: // Escape
			this.value = "";
			clearMessage();
			break;
	}
	if(config.options.chkIncrementalSearch) {
		if(this.value.length > 2) {
			if(this.value != this.getAttribute("lastSearchText")) {
				if(config.macros.search.timeout)
					clearTimeout(config.macros.search.timeout);
				var txt = this;
				config.macros.search.timeout = setTimeout(function() {config.macros.search.doSearch(txt);},500);
			}
		} else {
			if(config.macros.search.timeout)
				clearTimeout(config.macros.search.timeout);
		}
	}
};

config.macros.search.onFocus = function(e)
{
	this.select();
};

//--
//-- Tabs macro
//--

config.macros.tabs.handler = function(place,macroName,params)
{
	var cookie = params[0];
	var numTabs = (params.length-1)/3;
	var wrapper = createTiddlyElement(null,"div",null,"tabsetWrapper " + cookie);
	var tabset = createTiddlyElement(wrapper,"div",null,"tabset");
	tabset.setAttribute("cookie",cookie);
	var validTab = false;
	for(var t=0; t<numTabs; t++) {
		var label = params[t*3+1];
		var prompt = params[t*3+2];
		var content = params[t*3+3];
		var tab = createTiddlyButton(tabset,label,prompt,this.onClickTab,"tab tabUnselected");
		tab.setAttribute("tab",label);
		tab.setAttribute("content",content);
		tab.title = prompt;
		if(config.options[cookie] == label)
			validTab = true;
	}
	if(!validTab)
		config.options[cookie] = params[1];
	place.appendChild(wrapper);
	this.switchTab(tabset,config.options[cookie]);
};

config.macros.tabs.onClickTab = function(e)
{
	config.macros.tabs.switchTab(this.parentNode,this.getAttribute("tab"));
	return false;
};

config.macros.tabs.switchTab = function(tabset,tab)
{
	var cookie = tabset.getAttribute("cookie");
	var theTab = null;
	var nodes = tabset.childNodes;
	for(var t=0; t<nodes.length; t++) {
		if(nodes[t].getAttribute && nodes[t].getAttribute("tab") == tab) {
			theTab = nodes[t];
			theTab.className = "tab tabSelected";
		} else {
			nodes[t].className = "tab tabUnselected";
		}
	}
	if(theTab) {
		if(tabset.nextSibling && tabset.nextSibling.className == "tabContents")
			removeNode(tabset.nextSibling);
		var tabContent = createTiddlyElement(null,"div",null,"tabContents");
		tabset.parentNode.insertBefore(tabContent,tabset.nextSibling);
		var contentTitle = theTab.getAttribute("content");
		wikify(store.getTiddlerText(contentTitle),tabContent,null,store.getTiddler(contentTitle));
		if(cookie) {
			config.options[cookie] = tab;
			saveOptionCookie(cookie);
		}
	}
};

//--
//-- Tiddler toolbar
//--

// Create a toolbar command button
config.macros.toolbar.createCommand = function(place,commandName,tiddler,className)
{
	if(typeof commandName != "string") {
		var c = null;
		for(var t in config.commands) {
			if(config.commands[t] == commandName)
				c = t;
		}
		commandName = c;
	}
	if((tiddler instanceof Tiddler) && (typeof commandName == "string")) {
		var command = config.commands[commandName];
		if(command.isEnabled ? command.isEnabled(tiddler) : this.isCommandEnabled(command,tiddler)) {
			var text = command.getText ? command.getText(tiddler) : this.getCommandText(command,tiddler);
			var tooltip = command.getTooltip ? command.getTooltip(tiddler) : this.getCommandTooltip(command,tiddler);
			var cmd;
			switch(command.type) {
			case "popup":
				cmd = this.onClickPopup;
				break;
			case "command":
			default:
				cmd = this.onClickCommand;
				break;
			}
			var btn = createTiddlyButton(null,text,tooltip,cmd);
			btn.setAttribute("commandName",commandName);
			btn.setAttribute("tiddler",tiddler.title);
			addClass(btn,"command_" + commandName);
			if(className)
				addClass(btn,className);
			place.appendChild(btn);
		}
	}
};

config.macros.toolbar.isCommandEnabled = function(command,tiddler)
{
	var title = tiddler.title;
	var ro = tiddler.isReadOnly();
	var shadow = store.isShadowTiddler(title) && !store.tiddlerExists(title);
	return (!ro || (ro && !command.hideReadOnly)) && !(shadow && command.hideShadow);
};

config.macros.toolbar.getCommandText = function(command,tiddler)
{
	return tiddler.isReadOnly() && command.readOnlyText || command.text;
};

config.macros.toolbar.getCommandTooltip = function(command,tiddler)
{
	return tiddler.isReadOnly() && command.readOnlyTooltip || command.tooltip;
};

config.macros.toolbar.onClickCommand = function(ev)
{
	var e = ev || window.event;
	e.cancelBubble = true;
	if(e.stopPropagation) e.stopPropagation();
	var command = config.commands[this.getAttribute("commandName")];
	return command.handler(e,this,this.getAttribute("tiddler"));
};

config.macros.toolbar.onClickPopup = function(ev)
{
	var e = ev || window.event;
	e.cancelBubble = true;
	if(e.stopPropagation) e.stopPropagation();
	var popup = Popup.create(this);
	var command = config.commands[this.getAttribute("commandName")];
	var title = this.getAttribute("tiddler");
	var tiddler = store.fetchTiddler(title);
	popup.setAttribute("tiddler",title);
	command.handlePopup(popup,title);
	Popup.show();
	return false;
};

// Invoke the first command encountered from a given place that is tagged with a specified class
config.macros.toolbar.invokeCommand = function(place,className,event)
{
	var children = place.getElementsByTagName("a");
	for(var t=0; t<children.length; t++) {
		var c = children[t];
		if(hasClass(c,className) && c.getAttribute && c.getAttribute("commandName")) {
			if(c.onclick instanceof Function)
				c.onclick.call(c,event);
			break;
		}
	}
};

config.macros.toolbar.onClickMore = function(ev)
{
	var e = this.nextSibling;
	e.style.display = "inline";
	this.style.display = "none";
	return false;
};

config.macros.toolbar.onClickLess = function(ev)
{
	var e = this.parentNode;
	var m = e.previousSibling;
	e.style.display = "none";
	m.style.display = "inline";
	return false;
};

config.macros.toolbar.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	for(var t=0; t<params.length; t++) {
		var c = params[t];
		switch(c) {
		case "!":
			createTiddlyText(place,this.separator);
			break;
		case "*":
			createTiddlyElement(place,"br");
			break;
		case "<":
			var btn = createTiddlyButton(place,this.lessLabel,this.lessPrompt,config.macros.toolbar.onClickLess);
			addClass(btn,"lessCommand");
			break;
		case ">":
			var btn = createTiddlyButton(place,this.moreLabel,this.morePrompt,config.macros.toolbar.onClickMore);
			addClass(btn,"moreCommand");
			var e = createTiddlyElement(place,"span",null,"moreCommand");
			e.style.display = "none";
			place = e;
			break;
		default:
			var className = "";
			switch(c.substr(0,1)) {
			case "+":
				className = "defaultCommand";
				c = c.substr(1);
				break;
			case "-":
				className = "cancelCommand";
				c = c.substr(1);
				break;
			}
			if(c in config.commands)
				this.createCommand(place,c,tiddler,className);
			break;
		}
	}
};

//--
//-- Menu and toolbar commands
//--

config.commands.closeTiddler.handler = function(event,src,title)
{
	if(story.isDirty(title) && !readOnly) {
		if(!confirm(config.commands.cancelTiddler.warning.format([title])))
			return false;
	}
	story.setDirty(title,false);
	story.closeTiddler(title,true);
	return false;
};

config.commands.closeOthers.handler = function(event,src,title)
{
	story.closeAllTiddlers(title);
	return false;
};

config.commands.editTiddler.handler = function(event,src,title)
{
	clearMessage();
	var tiddlerElem = story.getTiddler(title);
	var fields = tiddlerElem.getAttribute("tiddlyFields");
	story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE,false,null,fields);
	story.focusTiddler(title,config.options.txtEditorFocus||"text");
	return false;
};

config.commands.saveTiddler.handler = function(event,src,title)
{
	var newTitle = story.saveTiddler(title,event.shiftKey);
	if(newTitle)
		story.displayTiddler(null,newTitle);
	return false;
};

config.commands.cancelTiddler.handler = function(event,src,title)
{
	if(story.hasChanges(title) && !readOnly) {
		if(!confirm(this.warning.format([title])))
			return false;
	}
	story.setDirty(title,false);
	story.displayTiddler(null,title);
	return false;
};

config.commands.deleteTiddler.handler = function(event,src,title)
{
	var deleteIt = true;
	if(config.options.chkConfirmDelete)
		deleteIt = confirm(this.warning.format([title]));
	if(deleteIt) {
		store.removeTiddler(title);
		story.closeTiddler(title,true);
		autoSaveChanges();
	}
	return false;
};

config.commands.permalink.handler = function(event,src,title)
{
	var t = encodeURIComponent(String.encodeTiddlyLink(title));
	if(window.location.hash != t)
		window.location.hash = t;
	return false;
};

config.commands.references.handlePopup = function(popup,title)
{
	var references = store.getReferringTiddlers(title);
	var c = false;
	for(var r=0; r<references.length; r++) {
		if(references[r].title != title && !references[r].isTagged("excludeLists")) {
			createTiddlyLink(createTiddlyElement(popup,"li"),references[r].title,true);
			c = true;
		}
	}
	if(!c)
		createTiddlyElement(popup,"li",null,"disabled",this.popupNone);
};

config.commands.jump.handlePopup = function(popup,title)
{
	story.forEachTiddler(function(title,element) {
		createTiddlyLink(createTiddlyElement(popup,"li"),title,true,null,false,null,true);
		});
};

config.commands.syncing.handlePopup = function(popup,title)
{
	var tiddler = store.fetchTiddler(title);
	if(!tiddler)
		return;
	var serverType = tiddler.getServerType();
	var serverHost = tiddler.fields["server.host"];
	var serverWorkspace = tiddler.fields["server.workspace"];
	if(!serverWorkspace)
		serverWorkspace = "";
	if(serverType) {
		var e = createTiddlyElement(popup,"li",null,"popupMessage");
		e.innerHTML = config.commands.syncing.currentlySyncing.format([serverType,serverHost,serverWorkspace]);
	} else {
		createTiddlyElement(popup,"li",null,"popupMessage",config.commands.syncing.notCurrentlySyncing);
	}
	if(serverType) {
		createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
		var btn = createTiddlyButton(createTiddlyElement(popup,"li"),this.captionUnSync,null,config.commands.syncing.onChooseServer);
		btn.setAttribute("tiddler",title);
		btn.setAttribute("server.type","");
	}
	createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
	createTiddlyElement(popup,"li",null,"popupMessage",config.commands.syncing.chooseServer);
	var feeds = store.getTaggedTiddlers("systemServer","title");
	for(var t=0; t<feeds.length; t++) {
		var f = feeds[t];
		var feedServerType = store.getTiddlerSlice(f.title,"Type");
		if(!feedServerType)
			feedServerType = "file";
		var feedServerHost = store.getTiddlerSlice(f.title,"URL");
		if(!feedServerHost)
			feedServerHost = "";
		var feedServerWorkspace = store.getTiddlerSlice(f.title,"Workspace");
		if(!feedServerWorkspace)
			feedServerWorkspace = "";
		var caption = f.title;
		if(serverType == feedServerType && serverHost == feedServerHost && serverWorkspace == feedServerWorkspace) {
			caption = config.commands.syncing.currServerMarker + caption;
		} else {
			caption = config.commands.syncing.notCurrServerMarker + caption;
		}
		btn = createTiddlyButton(createTiddlyElement(popup,"li"),caption,null,config.commands.syncing.onChooseServer);
		btn.setAttribute("tiddler",title);
		btn.setAttribute("server.type",feedServerType);
		btn.setAttribute("server.host",feedServerHost);
		btn.setAttribute("server.workspace",feedServerWorkspace);
	}
};

config.commands.syncing.onChooseServer = function(e)
{
	var tiddler = this.getAttribute("tiddler");
	var serverType = this.getAttribute("server.type");
	if(serverType) {
		store.addTiddlerFields(tiddler,{
			"server.type": serverType,
			"server.host": this.getAttribute("server.host"),
			"server.workspace": this.getAttribute("server.workspace")
			});
	} else {
		store.setValue(tiddler,"server",null);
	}
	return false;
};

config.commands.fields.handlePopup = function(popup,title)
{
	var tiddler = store.fetchTiddler(title);
	if(!tiddler)
		return;
	var items = [];
	store.forEachField(tiddler,function(tiddler,fieldName,value){items.push({field:fieldName,value:value});},true);
	items.sort(function(a,b) {return a.field < b.field ? -1 : (a.field == b.field ? 0 : +1);});
	if(items.length > 0)
		ListView.create(popup,items,this.listViewTemplate);
	else
		createTiddlyElement(popup,"div",null,null,this.emptyText);
};

//--
//-- Tiddler() object
//--

function Tiddler(title)
{
	this.title = title;
	this.text = "";
	this.modifier = null;
	this.created = new Date();
	this.modified = this.created;
	this.links = [];
	this.linksUpdated = false;
	this.tags = [];
	this.fields = {};
	return this;
}

Tiddler.prototype.getLinks = function()
{
	if(this.linksUpdated==false)
		this.changed();
	return this.links;
};

// Returns the fields that are inherited in string field:"value" field2:"value2" format
Tiddler.prototype.getInheritedFields = function()
{
	var f = {};
	for(var i in this.fields) {
		if(i=="server.host" || i=="server.workspace" || i=="wikiformat"|| i=="server.type") {
			f[i] = this.fields[i];
		}
	}
	return String.encodeHashMap(f);
};

// Increment the changeCount of a tiddler
Tiddler.prototype.incChangeCount = function()
{
	var c = this.fields['changecount'];
	c = c ? parseInt(c,10) : 0;
	this.fields['changecount'] = String(c+1);
};

// Clear the changeCount of a tiddler
Tiddler.prototype.clearChangeCount = function()
{
	if(this.fields['changecount']) {
		delete this.fields['changecount'];
	}
};

Tiddler.prototype.doNotSave = function()
{
	return this.fields['doNotSave'];
};

// Returns true if the tiddler has been updated since the tiddler was created or downloaded
Tiddler.prototype.isTouched = function()
{
	var changeCount = this.fields['changecount'];
	if(changeCount === undefined)
		changeCount = 0;
	return changeCount > 0;
};

// Change the text and other attributes of a tiddler
Tiddler.prototype.set = function(title,text,modifier,modified,tags,created,fields)
{
	this.assign(title,text,modifier,modified,tags,created,fields);
	this.changed();
	return this;
};

// Change the text and other attributes of a tiddler without triggered a tiddler.changed() call
Tiddler.prototype.assign = function(title,text,modifier,modified,tags,created,fields)
{
	if(title != undefined)
		this.title = title;
	if(text != undefined)
		this.text = text;
	if(modifier != undefined)
		this.modifier = modifier;
	if(modified != undefined)
		this.modified = modified;
	if(created != undefined)
		this.created = created;
	if(fields != undefined)
		this.fields = fields;
	if(tags != undefined)
		this.tags = (typeof tags == "string") ? tags.readBracketedList() : tags;
	else if(this.tags == undefined)
		this.tags = [];
	return this;
};

// Get the tags for a tiddler as a string (space delimited, using [[brackets]] for tags containing spaces)
Tiddler.prototype.getTags = function()
{
	return String.encodeTiddlyLinkList(this.tags);
};

// Test if a tiddler carries a tag
Tiddler.prototype.isTagged = function(tag)
{
	return this.tags.indexOf(tag) != -1;
};

// Static method to convert "\n" to newlines, "\s" to "\"
Tiddler.unescapeLineBreaks = function(text)
{
	return text ? text.unescapeLineBreaks() : "";
};

// Convert newlines to "\n", "\" to "\s"
Tiddler.prototype.escapeLineBreaks = function()
{
	return this.text.escapeLineBreaks();
};

// Updates the secondary information (like links[] array) after a change to a tiddler
Tiddler.prototype.changed = function()
{
	this.links = [];
	var text = this.text;
	// remove 'quoted' text before scanning tiddler source
	text = text.replace(/\/%((?:.|\n)*?)%\//g,"").
		replace(/\{{3}((?:.|\n)*?)\}{3}/g,"").
		replace(/"""((?:.|\n)*?)"""/g,"").
		replace(/\<nowiki\>((?:.|\n)*?)\<\/nowiki\>/g,"").
		replace(/\<html\>((?:.|\n)*?)\<\/html\>/g,"").
		replace(/\<script((?:.|\n)*?)\<\/script\>/g,"");
	var t = this.autoLinkWikiWords() ? 0 : 1;
	var tiddlerLinkRegExp = t==0 ? config.textPrimitives.tiddlerAnyLinkRegExp : config.textPrimitives.tiddlerForcedLinkRegExp;
	tiddlerLinkRegExp.lastIndex = 0;
	var formatMatch = tiddlerLinkRegExp.exec(text);
	while(formatMatch) {
		var lastIndex = tiddlerLinkRegExp.lastIndex;
		if(t==0 && formatMatch[1] && formatMatch[1] != this.title) {
			// wikiWordLink
			if(formatMatch.index > 0) {
				var preRegExp = new RegExp(config.textPrimitives.unWikiLink+"|"+config.textPrimitives.anyLetter,"mg");
				preRegExp.lastIndex = formatMatch.index-1;
				var preMatch = preRegExp.exec(text);
				if(preMatch.index != formatMatch.index-1)
					this.links.pushUnique(formatMatch[1]);
			} else {
				this.links.pushUnique(formatMatch[1]);
			}
		}
		else if(formatMatch[2-t] && !config.formatterHelpers.isExternalLink(formatMatch[3-t])) // titledBrackettedLink
			this.links.pushUnique(formatMatch[3-t]);
		else if(formatMatch[4-t] && formatMatch[4-t] != this.title) // brackettedLink
			this.links.pushUnique(formatMatch[4-t]);
		tiddlerLinkRegExp.lastIndex = lastIndex;
		formatMatch = tiddlerLinkRegExp.exec(text);
	}
	this.linksUpdated = true;
};

Tiddler.prototype.getSubtitle = function()
{
	var modifier = this.modifier;
	if(!modifier)
		modifier = config.messages.subtitleUnknown;
	var modified = this.modified;
	if(modified)
		modified = modified.toLocaleString();
	else
		modified = config.messages.subtitleUnknown;
	return config.messages.tiddlerLinkTooltip.format([this.title,modifier,modified]);
};

Tiddler.prototype.isReadOnly = function()
{
	return readOnly;
};

Tiddler.prototype.autoLinkWikiWords = function()
{
	return !(this.isTagged("systemConfig") || this.isTagged("excludeMissing"));
};

Tiddler.prototype.getServerType = function()
{
	var serverType = null;
	if(this.fields['server.type'])
		serverType = this.fields['server.type'];
	if(!serverType)
		serverType = this.fields['wikiformat'];
	if(serverType && !config.adaptors[serverType])
		serverType = null;
	return serverType;
};

Tiddler.prototype.getAdaptor = function()
{
	var serverType = this.getServerType();
	return serverType ? new config.adaptors[serverType]() : null;
};

//--
//-- TiddlyWiki() object contains Tiddler()s
//--

function TiddlyWiki()
{
	var tiddlers = {}; // Hashmap by name of tiddlers
	this.tiddlersUpdated = false;
	this.namedNotifications = []; // Array of {name:,notify:} of notification functions
	this.notificationLevel = 0;
	this.slices = {}; // map tiddlerName->(map sliceName->sliceValue). Lazy.
	this.clear = function() {
		tiddlers = {};
		this.setDirty(false);
	};
	this.fetchTiddler = function(title) {
		var t = tiddlers[title];
		return t instanceof Tiddler ? t : null;
	};
	this.deleteTiddler = function(title) {
		delete this.slices[title];
		delete tiddlers[title];
	};
	this.addTiddler = function(tiddler) {
		delete this.slices[tiddler.title];
		tiddlers[tiddler.title] = tiddler;
	};
	this.forEachTiddler = function(callback) {
		for(var t in tiddlers) {
			var tiddler = tiddlers[t];
			if(tiddler instanceof Tiddler)
				callback.call(this,t,tiddler);
		}
	};
}

TiddlyWiki.prototype.setDirty = function(dirty)
{
	this.dirty = dirty;
};

TiddlyWiki.prototype.isDirty = function()
{
	return this.dirty;
};

TiddlyWiki.prototype.tiddlerExists = function(title)
{
	var t = this.fetchTiddler(title);
	return t != undefined;
};

TiddlyWiki.prototype.isShadowTiddler = function(title)
{
	return config.shadowTiddlers[title] === undefined ? false : true;
};

TiddlyWiki.prototype.createTiddler = function(title)
{
	var tiddler = this.fetchTiddler(title);
	if(!tiddler) {
		tiddler = new Tiddler(title);
		this.addTiddler(tiddler);
		this.setDirty(true);
	}
	return tiddler;
};

TiddlyWiki.prototype.getTiddler = function(title)
{
	var t = this.fetchTiddler(title);
	if(t != undefined)
		return t;
	else
		return null;
};

TiddlyWiki.prototype.getShadowTiddlerText = function(title)
{
	if(typeof config.shadowTiddlers[title] == "string")
		return config.shadowTiddlers[title];
	else
		return "";
};

// Retrieve tiddler contents
TiddlyWiki.prototype.getTiddlerText = function(title,defaultText)
{
	if(!title)
		return defaultText;
	var pos = title.indexOf(config.textPrimitives.sectionSeparator);
	var section = null;
	if(pos != -1) {
		section = title.substr(pos + config.textPrimitives.sectionSeparator.length);
		title = title.substr(0,pos);
	}
	pos = title.indexOf(config.textPrimitives.sliceSeparator);
	if(pos != -1) {
		var slice = this.getTiddlerSlice(title.substr(0,pos),title.substr(pos + config.textPrimitives.sliceSeparator.length));
		if(slice)
			return slice;
	}
	var tiddler = this.fetchTiddler(title);
	if(tiddler) {
		if(!section)
			return tiddler.text;
		var re = new RegExp("(^!{1,6}" + section.escapeRegExp() + "[ \t]*\n)","mg");
		re.lastIndex = 0;
		var match = re.exec(tiddler.text);
		if(match) {
			var t = tiddler.text.substr(match.index+match[1].length);
			var re2 = /^!/mg;
			re2.lastIndex = 0;
			match = re2.exec(t); //# search for the next heading
			if(match)
				t = t.substr(0,match.index-1);//# don't include final \n
			return t;
		}
		return defaultText;
	}
	if(this.isShadowTiddler(title))
		return this.getShadowTiddlerText(title);
	if(defaultText != undefined)
		return defaultText;
	return null;
};

TiddlyWiki.prototype.getRecursiveTiddlerText = function(title,defaultText,depth)
{
	var bracketRegExp = new RegExp("(?:\\[\\[([^\\]]+)\\]\\])","mg");
	var text = this.getTiddlerText(title,null);
	if(text == null)
		return defaultText;
	var textOut = [];
	var lastPos = 0;
	do {
		var match = bracketRegExp.exec(text);
		if(match) {
			textOut.push(text.substr(lastPos,match.index-lastPos));
			if(match[1]) {
				if(depth <= 0)
					textOut.push(match[1]);
				else
					textOut.push(this.getRecursiveTiddlerText(match[1],"[[" + match[1] + "]]",depth-1));
			}
			lastPos = match.index + match[0].length;
		} else {
			textOut.push(text.substr(lastPos));
		}
	} while(match);
	return textOut.join("");
};

TiddlyWiki.prototype.slicesRE = /(?:^([\'\/]{0,2})~?([\.\w]+)\:\1[\t\x20]*([^\n]+)[\t\x20]*$)|(?:^\|([\'\/]{0,2})~?([\.\w]+)\:?\4\|[\t\x20]*([^\n]+)[\t\x20]*\|$)/gm;

// @internal
TiddlyWiki.prototype.calcAllSlices = function(title)
{
	var slices = {};
	var text = this.getTiddlerText(title,"");
	this.slicesRE.lastIndex = 0;
	var m = this.slicesRE.exec(text);
	while(m) {
		if(m[2])
			slices[m[2]] = m[3];
		else
			slices[m[5]] = m[6];
		m = this.slicesRE.exec(text);
	}
	return slices;
};

// Returns the slice of text of the given name
TiddlyWiki.prototype.getTiddlerSlice = function(title,sliceName)
{
	var slices = this.slices[title];
	if(!slices) {
		slices = this.calcAllSlices(title);
		this.slices[title] = slices;
	}
	return slices[sliceName];
};

// Build an hashmap of the specified named slices of a tiddler
TiddlyWiki.prototype.getTiddlerSlices = function(title,sliceNames)
{
	var r = {};
	for(var t=0; t<sliceNames.length; t++) {
		var slice = this.getTiddlerSlice(title,sliceNames[t]);
		if(slice)
			r[sliceNames[t]] = slice;
	}
	return r;
};

TiddlyWiki.prototype.suspendNotifications = function()
{
	this.notificationLevel--;
};

TiddlyWiki.prototype.resumeNotifications = function()
{
	this.notificationLevel++;
};

// Invoke the notification handlers for a particular tiddler
TiddlyWiki.prototype.notify = function(title,doBlanket)
{
	if(!this.notificationLevel) {
		for(var t=0; t<this.namedNotifications.length; t++) {
			var n = this.namedNotifications[t];
			if((n.name == null && doBlanket) || (n.name == title))
				n.notify(title);
		}
	}
};

// Invoke the notification handlers for all tiddlers
TiddlyWiki.prototype.notifyAll = function()
{
	if(!this.notificationLevel) {
		for(var t=0; t<this.namedNotifications.length; t++) {
			var n = this.namedNotifications[t];
			if(n.name)
				n.notify(n.name);
		}
	}
};

// Add a notification handler to a tiddler
TiddlyWiki.prototype.addNotification = function(title,fn)
{
	for(var i=0; i<this.namedNotifications.length; i++) {
		if((this.namedNotifications[i].name == title) && (this.namedNotifications[i].notify == fn))
			return this;
	}
	this.namedNotifications.push({name: title, notify: fn});
	return this;
};

TiddlyWiki.prototype.removeTiddler = function(title)
{
	var tiddler = this.fetchTiddler(title);
	if(tiddler) {
		this.deleteTiddler(title);
		this.notify(title,true);
		this.setDirty(true);
	}
};

// Reset the sync status of a freshly synced tiddler
TiddlyWiki.prototype.resetTiddler = function(title)
{
	var tiddler = this.fetchTiddler(title);
	if(tiddler) {
		tiddler.clearChangeCount();
		this.notify(title,true);
		this.setDirty(true);
	}
};

TiddlyWiki.prototype.setTiddlerTag = function(title,status,tag)
{
	var tiddler = this.fetchTiddler(title);
	if(tiddler) {
		var t = tiddler.tags.indexOf(tag);
		if(t != -1)
			tiddler.tags.splice(t,1);
		if(status)
			tiddler.tags.push(tag);
		tiddler.changed();
		tiddler.incChangeCount();
		this.notify(title,true);
		this.setDirty(true);
	}
};

TiddlyWiki.prototype.addTiddlerFields = function(title,fields)
{
	var tiddler = this.fetchTiddler(title);
	if(!tiddler)
		return;
	merge(tiddler.fields,fields);
	tiddler.changed();
	tiddler.incChangeCount();
	this.notify(title,true);
	this.setDirty(true);
};

// Store tiddler in TiddlyWiki instance
TiddlyWiki.prototype.saveTiddler = function(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created)
{
	var tiddler = this.fetchTiddler(title);
	if(tiddler) {
		created = created || tiddler.created; // Preserve created date
		this.deleteTiddler(title);
	} else {
		created = created || modified;
		tiddler = new Tiddler();
	}
	tiddler.set(newTitle,newBody,modifier,modified,tags,created,fields);
	this.addTiddler(tiddler);
	if(clearChangeCount)
		tiddler.clearChangeCount();
	else
		tiddler.incChangeCount();
	if(title != newTitle)
		this.notify(title,true);
	this.notify(newTitle,true);
	this.setDirty(true);
	return tiddler;
};

TiddlyWiki.prototype.incChangeCount = function(title)
{
	var tiddler = this.fetchTiddler(title);
	if(tiddler)
		tiddler.incChangeCount();
};

TiddlyWiki.prototype.getLoader = function()
{
	if(!this.loader)
		this.loader = new TW21Loader();
	return this.loader;
};

TiddlyWiki.prototype.getSaver = function()
{
	if(!this.saver)
		this.saver = new TW21Saver();
	return this.saver;
};

// Return all tiddlers formatted as an HTML string
TiddlyWiki.prototype.allTiddlersAsHtml = function()
{
	return this.getSaver().externalize(store);
};

// Load contents of a TiddlyWiki from an HTML DIV
TiddlyWiki.prototype.loadFromDiv = function(src,idPrefix,noUpdate)
{
	this.idPrefix = idPrefix;
	var storeElem = (typeof src == "string") ? document.getElementById(src) : src;
	if(!storeElem)
		return;
	var tiddlers = this.getLoader().loadTiddlers(this,storeElem.childNodes);
	this.setDirty(false);
	if(!noUpdate) {
		for(var i = 0;i<tiddlers.length; i++)
			tiddlers[i].changed();
	}
	jQuery().trigger("loadTiddlers");
};

// Load contents of a TiddlyWiki from a string
// Returns null if there's an error
TiddlyWiki.prototype.importTiddlyWiki = function(text)
{
	var posDiv = locateStoreArea(text);
	if(!posDiv)
		return null;
	var content = "<" + "html><" + "body>" + text.substring(posDiv[0],posDiv[1] + endSaveArea.length) + "<" + "/body><" + "/html>";
	// Create the iframe
	var iframe = document.createElement("iframe");
	iframe.style.display = "none";
	document.body.appendChild(iframe);
	var doc = iframe.document;
	if(iframe.contentDocument)
		doc = iframe.contentDocument; // For NS6
	else if(iframe.contentWindow)
		doc = iframe.contentWindow.document; // For IE5.5 and IE6
	// Put the content in the iframe
	doc.open();
	doc.writeln(content);
	doc.close();
	// Load the content into a TiddlyWiki() object
	var storeArea = doc.getElementById("storeArea");
	this.loadFromDiv(storeArea,"store");
	// Get rid of the iframe
	iframe.parentNode.removeChild(iframe);
	return this;
};

TiddlyWiki.prototype.updateTiddlers = function()
{
	this.tiddlersUpdated = true;
	this.forEachTiddler(function(title,tiddler) {
		tiddler.changed();
	});
};

// Return an array of tiddlers matching a search regular expression
TiddlyWiki.prototype.search = function(searchRegExp,sortField,excludeTag,match)
{
	var candidates = this.reverseLookup("tags",excludeTag,!!match);
	var results = [];
	for(var t=0; t<candidates.length; t++) {
		if((candidates[t].title.search(searchRegExp) != -1) || (candidates[t].text.search(searchRegExp) != -1))
			results.push(candidates[t]);
	}
	if(!sortField)
		sortField = "title";
	results.sort(function(a,b) {return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);});
	return results;
};

// Returns a list of all tags in use
//   excludeTag - if present, excludes tags that are themselves tagged with excludeTag
// Returns an array of arrays where [tag][0] is the name of the tag and [tag][1] is the number of occurances
TiddlyWiki.prototype.getTags = function(excludeTag)
{
	var results = [];
	this.forEachTiddler(function(title,tiddler) {
		for(var g=0; g<tiddler.tags.length; g++) {
			var tag = tiddler.tags[g];
			var n = true;
			for(var c=0; c<results.length; c++) {
				if(results[c][0] == tag) {
					n = false;
					results[c][1]++;
				}
			}
			if(n && excludeTag) {
				var t = this.fetchTiddler(tag);
				if(t && t.isTagged(excludeTag))
					n = false;
			}
			if(n)
				results.push([tag,1]);
		}
	});
	results.sort(function(a,b) {return a[0].toLowerCase() < b[0].toLowerCase() ? -1 : (a[0].toLowerCase() == b[0].toLowerCase() ? 0 : +1);});
	return results;
};

// Return an array of the tiddlers that are tagged with a given tag
TiddlyWiki.prototype.getTaggedTiddlers = function(tag,sortField)
{
	return this.reverseLookup("tags",tag,true,sortField);
};

// Return an array of the tiddlers that link to a given tiddler
TiddlyWiki.prototype.getReferringTiddlers = function(title,unusedParameter,sortField)
{
	if(!this.tiddlersUpdated)
		this.updateTiddlers();
	return this.reverseLookup("links",title,true,sortField);
};

// Return an array of the tiddlers that do or do not have a specified entry in the specified storage array (ie, "links" or "tags")
// lookupMatch == true to match tiddlers, false to exclude tiddlers
TiddlyWiki.prototype.reverseLookup = function(lookupField,lookupValue,lookupMatch,sortField)
{
	var results = [];
	this.forEachTiddler(function(title,tiddler) {
		var f = !lookupMatch;
		for(var lookup=0; lookup<tiddler[lookupField].length; lookup++) {
			if(tiddler[lookupField][lookup] == lookupValue)
				f = lookupMatch;
		}
		if(f)
			results.push(tiddler);
	});
	if(!sortField)
		sortField = "title";
	results.sort(function(a,b) {return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);});
	return results;
};

// Return the tiddlers as a sorted array
TiddlyWiki.prototype.getTiddlers = function(field,excludeTag)
{
	var results = [];
	this.forEachTiddler(function(title,tiddler) {
		if(excludeTag == undefined || !tiddler.isTagged(excludeTag))
			results.push(tiddler);
	});
	if(field)
		results.sort(function(a,b) {return a[field] < b[field] ? -1 : (a[field] == b[field] ? 0 : +1);});
	return results;
};

// Return array of names of tiddlers that are referred to but not defined
TiddlyWiki.prototype.getMissingLinks = function(sortField)
{
	if(!this.tiddlersUpdated)
		this.updateTiddlers();
	var results = [];
	this.forEachTiddler(function (title,tiddler) {
		if(tiddler.isTagged("excludeMissing") || tiddler.isTagged("systemConfig"))
			return;
		for(var n=0; n<tiddler.links.length;n++) {
			var link = tiddler.links[n];
			if(this.fetchTiddler(link) == null && !this.isShadowTiddler(link))
				results.pushUnique(link);
		}
	});
	results.sort();
	return results;
};

// Return an array of names of tiddlers that are defined but not referred to
TiddlyWiki.prototype.getOrphans = function()
{
	var results = [];
	this.forEachTiddler(function (title,tiddler) {
		if(this.getReferringTiddlers(title).length == 0 && !tiddler.isTagged("excludeLists"))
			results.push(title);
	});
	results.sort();
	return results;
};

// Return an array of names of all the shadow tiddlers
TiddlyWiki.prototype.getShadowed = function()
{
	var results = [];
	for(var t in config.shadowTiddlers) {
		if(this.isShadowTiddler(t))
			results.push(t);
	}
	results.sort();
	return results;
};

// Return an array of tiddlers that have been touched since they were downloaded or created
TiddlyWiki.prototype.getTouched = function()
{
	var results = [];
	this.forEachTiddler(function(title,tiddler) {
		if(tiddler.isTouched())
			results.push(tiddler);
		});
	results.sort();
	return results;
};

// Resolves a Tiddler reference or tiddler title into a Tiddler object, or null if it doesn't exist
TiddlyWiki.prototype.resolveTiddler = function(tiddler)
{
	var t = (typeof tiddler == "string") ? this.getTiddler(tiddler) : tiddler;
	return t instanceof Tiddler ? t : null;
};

// Filter a list of tiddlers
TiddlyWiki.prototype.filterTiddlers = function(filter)
{
	var results = [];
	if(filter) {
		var tiddler;
		var re = /([^\s\[\]]+)|(?:\[([ \w]+)\[([^\]]+)\]\])|(?:\[\[([^\]]+)\]\])/mg;
		var match = re.exec(filter);
		while(match) {
			if(match[1] || match[4]) {
				var title = match[1] || match[4];
				tiddler = this.fetchTiddler(title);
				if(tiddler) {
					results.pushUnique(tiddler);
				} else if(this.isShadowTiddler(title)) {
					tiddler = new Tiddler();
					tiddler.set(title,this.getTiddlerText(title));
					results.pushUnique(tiddler);
				} else {
					results.pushUnique(new Tiddler(title));
				}
			} else if(match[2]) {
				switch(match[2]) {
					case "tag":
						var matched = this.getTaggedTiddlers(match[3]);
						for(var m = 0; m < matched.length; m++)
							results.pushUnique(matched[m]);
						break;
					case "sort":
						results = this.sortTiddlers(results,match[3]);
						break;
				}
			}
			match = re.exec(filter);
		}
	}
	return results;
};

// Sort a list of tiddlers
TiddlyWiki.prototype.sortTiddlers = function(tiddlers,field)
{
	var asc = +1;
	switch(field.substr(0,1)) {
	case "-":
		asc = -1;
		// Note: this fall-through is intentional
		/*jsl:fallthru*/
	case "+":
		field = field.substr(1);
		break;
	}
	if(TiddlyWiki.standardFieldAccess[field])
		tiddlers.sort(function(a,b) {return a[field] < b[field] ? -asc : (a[field] == b[field] ? 0 : asc);});
	else
		tiddlers.sort(function(a,b) {return a.fields[field] < b.fields[field] ? -asc : (a.fields[field] == b.fields[field] ? 0 : +asc);});
	return tiddlers;
};

// Returns true if path is a valid field name (path),
// i.e. a sequence of identifiers, separated by "."
TiddlyWiki.isValidFieldName = function(name)
{
	var match = /[a-zA-Z_]\w*(\.[a-zA-Z_]\w*)*/.exec(name);
	return match && (match[0] == name);
};

// Throws an exception when name is not a valid field name.
TiddlyWiki.checkFieldName = function(name)
{
	if(!TiddlyWiki.isValidFieldName(name))
		throw config.messages.invalidFieldName.format([name]);
};

function StringFieldAccess(n,readOnly)
{
	this.set = readOnly ?
			function(t,v) {if(v != t[n]) throw config.messages.fieldCannotBeChanged.format([n]);} :
			function(t,v) {if(v != t[n]) {t[n] = v; return true;}};
	this.get = function(t) {return t[n];};
}

function DateFieldAccess(n)
{
	this.set = function(t,v) {
		var d = v instanceof Date ? v : Date.convertFromYYYYMMDDHHMM(v);
		if(d != t[n]) {
			t[n] = d; return true;
		}
	};
	this.get = function(t) {return t[n].convertToYYYYMMDDHHMM();};
}

function LinksFieldAccess(n)
{
	this.set = function(t,v) {
		var s = (typeof v == "string") ? v.readBracketedList() : v;
		if(s.toString() != t[n].toString()) {
			t[n] = s; return true;
		}
	};
	this.get = function(t) {return String.encodeTiddlyLinkList(t[n]);};
}

TiddlyWiki.standardFieldAccess = {
	// The set functions return true when setting the data has changed the value.
	"title":    new StringFieldAccess("title",true),
	// Handle the "tiddler" field name as the title
	"tiddler":  new StringFieldAccess("title",true),
	"text":     new StringFieldAccess("text"),
	"modifier": new StringFieldAccess("modifier"),
	"modified": new DateFieldAccess("modified"),
	"created":  new DateFieldAccess("created"),
	"tags":     new LinksFieldAccess("tags")
};

TiddlyWiki.isStandardField = function(name)
{
	return TiddlyWiki.standardFieldAccess[name] != undefined;
};

// Sets the value of the given field of the tiddler to the value.
// Setting an ExtendedField's value to null or undefined removes the field.
// Setting a namespace to undefined removes all fields of that namespace.
// The fieldName is case-insensitive.
// All values will be converted to a string value.
TiddlyWiki.prototype.setValue = function(tiddler,fieldName,value)
{
	TiddlyWiki.checkFieldName(fieldName);
	var t = this.resolveTiddler(tiddler);
	if(!t)
		return;
	fieldName = fieldName.toLowerCase();
	var isRemove = (value === undefined) || (value === null);
	var accessor = TiddlyWiki.standardFieldAccess[fieldName];
	if(accessor) {
		if(isRemove)
			// don't remove StandardFields
			return;
		var h = TiddlyWiki.standardFieldAccess[fieldName];
		if(!h.set(t,value))
			return;
	} else {
		var oldValue = t.fields[fieldName];
		if(isRemove) {
			if(oldValue !== undefined) {
				// deletes a single field
				delete t.fields[fieldName];
			} else {
				// no concrete value is defined for the fieldName
				// so we guess this is a namespace path.
				// delete all fields in a namespace
				var re = new RegExp("^"+fieldName+"\\.");
				var dirty = false;
				for(var n in t.fields) {
					if(n.match(re)) {
						delete t.fields[n];
						dirty = true;
					}
				}
				if(!dirty)
					return;
			}
		} else {
			// the "normal" set case. value is defined (not null/undefined)
			// For convenience provide a nicer conversion Date->String
			value = value instanceof Date ? value.convertToYYYYMMDDHHMMSSMMM() : String(value);
			if(oldValue == value)
				return;
			t.fields[fieldName] = value;
		}
	}
	// When we are here the tiddler/store really was changed.
	this.notify(t.title,true);
	if(!fieldName.match(/^temp\./))
		this.setDirty(true);
};

// Returns the value of the given field of the tiddler.
// The fieldName is case-insensitive.
// Will only return String values (or undefined).
TiddlyWiki.prototype.getValue = function(tiddler,fieldName)
{
	var t = this.resolveTiddler(tiddler);
	if(!t)
		return undefined;
	fieldName = fieldName.toLowerCase();
	var accessor = TiddlyWiki.standardFieldAccess[fieldName];
	if(accessor) {
		return accessor.get(t);
	}
	return t.fields[fieldName];
};

// Calls the callback function for every field in the tiddler.
// When callback function returns a non-false value the iteration stops
// and that value is returned.
// The order of the fields is not defined.
// @param callback a function(tiddler,fieldName,value).
TiddlyWiki.prototype.forEachField = function(tiddler,callback,onlyExtendedFields)
{
	var t = this.resolveTiddler(tiddler);
	if(!t)
		return undefined;
	var n,result;
	for(n in t.fields) {
		result = callback(t,n,t.fields[n]);
		if(result)
			return result;
		}
	if(onlyExtendedFields)
		return undefined;
	for(n in TiddlyWiki.standardFieldAccess) {
		if(n == "tiddler")
			// even though the "title" field can also be referenced through the name "tiddler"
			// we only visit this field once.
			continue;
		result = callback(t,n,TiddlyWiki.standardFieldAccess[n].get(t));
		if(result)
			return result;
	}
	return undefined;
};

//--
//-- Story functions
//--

function Story(containerId,idPrefix)
{
	this.container = containerId;
	this.idPrefix = idPrefix;
	this.highlightRegExp = null;
	this.tiddlerId = function(title) {
		var id = this.idPrefix + title;
		return id==this.container ? this.idPrefix + "_" + title : id;
	};
	this.containerId = function() {
		return this.container;
	};
}

Story.prototype.getTiddler = function(title)
{
	return document.getElementById(this.tiddlerId(title));
};

Story.prototype.getContainer = function()
{
	return document.getElementById(this.containerId());
};

Story.prototype.forEachTiddler = function(fn)
{
	var place = this.getContainer();
	if(!place)
		return;
	var e = place.firstChild;
	while(e) {
		var n = e.nextSibling;
		var title = e.getAttribute("tiddler");
		fn.call(this,title,e);
		e = n;
	}
};

Story.prototype.displayDefaultTiddlers = function()
{
	this.displayTiddlers(null,store.filterTiddlers(store.getTiddlerText("DefaultTiddlers")));
};

Story.prototype.displayTiddlers = function(srcElement,titles,template,animate,unused,customFields,toggle)
{
	for(var t = titles.length-1;t>=0;t--)
		this.displayTiddler(srcElement,titles[t],template,animate,unused,customFields);
};

Story.prototype.displayTiddler = function(srcElement,tiddler,template,animate,unused,customFields,toggle,animationSrc)
{
	var title = (tiddler instanceof Tiddler) ? tiddler.title : tiddler;
	var tiddlerElem = this.getTiddler(title);
	if(tiddlerElem) {
		if(toggle)
			this.closeTiddler(title,true);
		else
			this.refreshTiddler(title,template,false,customFields);
	} else {
		var place = this.getContainer();
		var before = this.positionTiddler(srcElement);
		tiddlerElem = this.createTiddler(place,before,title,template,customFields);
	}
	if(animationSrc && typeof animationSrc !== "string") {
		srcElement = animationSrc;
	}
	if(srcElement && typeof srcElement !== "string") {
		if(config.options.chkAnimate && (animate == undefined || animate == true) && anim && typeof Zoomer == "function" && typeof Scroller == "function")
			anim.startAnimating(new Zoomer(title,srcElement,tiddlerElem),new Scroller(tiddlerElem));
		else
			window.scrollTo(0,ensureVisible(tiddlerElem));
	}
};

Story.prototype.positionTiddler = function(srcElement)
{
	var place = this.getContainer();
	var before = null;
	if(typeof srcElement == "string") {
		switch(srcElement) {
		case "top":
			before = place.firstChild;
			break;
		case "bottom":
			before = null;
			break;
		}
	} else {
		var after = this.findContainingTiddler(srcElement);
		if(after == null) {
			before = place.firstChild;
		} else if(after.nextSibling) {
			before = after.nextSibling;
			if(before.nodeType != 1)
				before = null;
		}
	}
	return before;
};

Story.prototype.createTiddler = function(place,before,title,template,customFields)
{
	var tiddlerElem = createTiddlyElement(null,"div",this.tiddlerId(title),"tiddler");
	tiddlerElem.setAttribute("refresh","tiddler");
	if(customFields)
		tiddlerElem.setAttribute("tiddlyFields",customFields);
	place.insertBefore(tiddlerElem,before);
	var defaultText = null;
	if(!store.tiddlerExists(title) && !store.isShadowTiddler(title))
		defaultText = this.loadMissingTiddler(title,customFields,tiddlerElem);
	this.refreshTiddler(title,template,false,customFields,defaultText);
	return tiddlerElem;
};

Story.prototype.loadMissingTiddler = function(title,fields,tiddlerElem)
{
	var getTiddlerCallback = function(context)
	{
		if(context.status) {
			var t = context.tiddler;
			if(!t.created)
				t.created = new Date();
			if(!t.modified)
				t.modified = t.created;
			store.saveTiddler(t.title,t.title,t.text,t.modifier,t.modified,t.tags,t.fields,true,t.created);
			autoSaveChanges();
		} else {
			story.refreshTiddler(context.title,null,true);
		}
		context.adaptor.close();
		delete context.adaptor;
	};
	var tiddler = new Tiddler(title);
	tiddler.fields = typeof fields == "string" ? fields.decodeHashMap() : fields||{};
	var context = {serverType:tiddler.getServerType()};
	if(!context.serverType)
		return;
	context.host = tiddler.fields['server.host'];
	context.workspace = tiddler.fields['server.workspace'];
	var adaptor = new config.adaptors[context.serverType];
	adaptor.getTiddler(title,context,null,getTiddlerCallback);
	return config.messages.loadingMissingTiddler.format([title,context.serverType,context.host,context.workspace]);
};

Story.prototype.chooseTemplateForTiddler = function(title,template)
{
	if(!template)
		template = DEFAULT_VIEW_TEMPLATE;
	if(template == DEFAULT_VIEW_TEMPLATE || template == DEFAULT_EDIT_TEMPLATE)
		template = config.tiddlerTemplates[template];
	return template;
};

Story.prototype.getTemplateForTiddler = function(title,template,tiddler)
{
	return store.getRecursiveTiddlerText(template,null,10);
};

Story.prototype.refreshTiddler = function(title,template,force,customFields,defaultText)
{
	var tiddlerElem = this.getTiddler(title);
	if(tiddlerElem) {
		if(tiddlerElem.getAttribute("dirty") == "true" && !force)
			return tiddlerElem;
		template = this.chooseTemplateForTiddler(title,template);
		var currTemplate = tiddlerElem.getAttribute("template");
		if((template != currTemplate) || force) {
			var tiddler = store.getTiddler(title);
			if(!tiddler) {
				tiddler = new Tiddler();
				if(store.isShadowTiddler(title)) {
					var tags = [];
					tiddler.set(title,store.getTiddlerText(title),config.views.wikified.shadowModifier,version.date,tags,version.date);
				} else {
					var text = template=="EditTemplate" ?
								config.views.editor.defaultText.format([title]) :
								config.views.wikified.defaultText.format([title]);
					text = defaultText || text;
					var fields = customFields ? customFields.decodeHashMap() : null;
					tiddler.set(title,text,config.views.wikified.defaultModifier,version.date,[],version.date,fields);
				}
			}
			tiddlerElem.setAttribute("tags",tiddler.tags.join(" "));
			tiddlerElem.setAttribute("tiddler",title);
			tiddlerElem.setAttribute("template",template);
			tiddlerElem.onmouseover = this.onTiddlerMouseOver;
			tiddlerElem.onmouseout = this.onTiddlerMouseOut;
			tiddlerElem.ondblclick = this.onTiddlerDblClick;
			tiddlerElem[window.event?"onkeydown":"onkeypress"] = this.onTiddlerKeyPress;
			tiddlerElem.innerHTML = this.getTemplateForTiddler(title,template,tiddler);
			applyHtmlMacros(tiddlerElem,tiddler);
			if(store.getTaggedTiddlers(title).length > 0)
				addClass(tiddlerElem,"isTag");
			else
				removeClass(tiddlerElem,"isTag");
			if(store.tiddlerExists(title)) {
				removeClass(tiddlerElem,"shadow");
				removeClass(tiddlerElem,"missing");
			} else {
				addClass(tiddlerElem, store.isShadowTiddler(title) ? "shadow" : "missing");
			}
			if(customFields)
				this.addCustomFields(tiddlerElem,customFields);
			forceReflow();
		}
	}
	return tiddlerElem;
};

Story.prototype.addCustomFields = function(place,customFields)
{
	var fields = customFields.decodeHashMap();
	var w = createTiddlyElement(place,"div",null,"customFields");
	w.style.display = "none";
	for(var t in fields) {
		var e = document.createElement("input");
		e.setAttribute("type","text");
		e.setAttribute("value",fields[t]);
		w.appendChild(e);
		e.setAttribute("edit",t);
	}
};

Story.prototype.refreshAllTiddlers = function(force)
{
	var e = this.getContainer().firstChild;
	while(e) {
		var template = e.getAttribute("template");
		if(template && e.getAttribute("dirty") != "true") {
			this.refreshTiddler(e.getAttribute("tiddler"),force ? null : template,true);
		}
		e = e.nextSibling;
	}
};

Story.prototype.onTiddlerMouseOver = function(e)
{
	addClass(this, "selected");
};

Story.prototype.onTiddlerMouseOut = function(e)
{
	removeClass(this,"selected");
};

Story.prototype.onTiddlerDblClick = function(ev)
{
	var e = ev || window.event;
	var target = resolveTarget(e);
	if(target && target.nodeName.toLowerCase() != "input" && target.nodeName.toLowerCase() != "textarea") {
		if(document.selection && document.selection.empty)
			document.selection.empty();
		config.macros.toolbar.invokeCommand(this,"defaultCommand",e);
		e.cancelBubble = true;
		if(e.stopPropagation) e.stopPropagation();
		return true;
	}
	return false;
};

Story.prototype.onTiddlerKeyPress = function(ev)
{
	var e = ev || window.event;
	clearMessage();
	var consume = false;
	var title = this.getAttribute("tiddler");
	var target = resolveTarget(e);
	switch(e.keyCode) {
	case 9: // Tab
		if(config.options.chkInsertTabs && target.tagName.toLowerCase() == "textarea") {
			replaceSelection(target,String.fromCharCode(9));
			consume = true;
		}
		if(config.isOpera) {
			target.onblur = function() {
				this.focus();
				this.onblur = null;
			};
		}
		break;
	case 13: // Ctrl-Enter
	case 10: // Ctrl-Enter on IE PC
	case 77: // Ctrl-Enter is "M" on some platforms
		if(e.ctrlKey) {
			blurElement(this);
			config.macros.toolbar.invokeCommand(this,"defaultCommand",e);
			consume = true;
		}
		break;
	case 27: // Escape
		blurElement(this);
		config.macros.toolbar.invokeCommand(this,"cancelCommand",e);
		consume = true;
		break;
	}
	e.cancelBubble = consume;
	if(consume) {
		if(e.stopPropagation) e.stopPropagation(); // Stop Propagation
		e.returnValue = true; // Cancel The Event in IE
		if(e.preventDefault ) e.preventDefault(); // Cancel The Event in Moz
	}
	return !consume;
};

Story.prototype.getTiddlerField = function(title,field)
{
	var tiddlerElem = this.getTiddler(title);
	var e = null;
	if(tiddlerElem ) {
		var children = tiddlerElem.getElementsByTagName("*");
		for(var t=0; t<children.length; t++) {
			var c = children[t];
			if(c.tagName.toLowerCase() == "input" || c.tagName.toLowerCase() == "textarea") {
				if(!e)
					e = c;
				if(c.getAttribute("edit") == field)
					e = c;
			}
		}
	}
	return e;
};

Story.prototype.focusTiddler = function(title,field)
{
	var e = this.getTiddlerField(title,field);
	if(e) {
		e.focus();
		e.select();
	}
};

Story.prototype.blurTiddler = function(title)
{
	var tiddlerElem = this.getTiddler(title);
	if(tiddlerElem && tiddlerElem.focus && tiddlerElem.blur) {
		tiddlerElem.focus();
		tiddlerElem.blur();
	}
};

Story.prototype.setTiddlerField = function(title,tag,mode,field)
{
	var c = this.getTiddlerField(title,field);
	var tags = c.value.readBracketedList();
	tags.setItem(tag,mode);
	c.value = String.encodeTiddlyLinkList(tags);
};

Story.prototype.setTiddlerTag = function(title,tag,mode)
{
	this.setTiddlerField(title,tag,mode,"tags");
};

Story.prototype.closeTiddler = function(title,animate,unused)
{
	var tiddlerElem = this.getTiddler(title);
	if(tiddlerElem) {
		clearMessage();
		this.scrubTiddler(tiddlerElem);
		if(config.options.chkAnimate && animate && anim && typeof Slider == "function")
			anim.startAnimating(new Slider(tiddlerElem,false,null,"all"));
		else {
			removeNode(tiddlerElem);
			forceReflow();
		}
	}
};

Story.prototype.scrubTiddler = function(tiddlerElem)
{
	tiddlerElem.id = null;
};

Story.prototype.setDirty = function(title,dirty)
{
	var tiddlerElem = this.getTiddler(title);
	if(tiddlerElem)
		tiddlerElem.setAttribute("dirty",dirty ? "true" : "false");
};

Story.prototype.isDirty = function(title)
{
	var tiddlerElem = this.getTiddler(title);
	if(tiddlerElem)
		return tiddlerElem.getAttribute("dirty") == "true";
	return null;
};

Story.prototype.areAnyDirty = function()
{
	var r = false;
	this.forEachTiddler(function(title,element) {
		if(this.isDirty(title))
			r = true;
	});
	return r;
};

Story.prototype.closeAllTiddlers = function(exclude)
{
	clearMessage();
	this.forEachTiddler(function(title,element) {
		if((title != exclude) && element.getAttribute("dirty") != "true")
			this.closeTiddler(title);
	});
	window.scrollTo(0,ensureVisible(this.container));
};

Story.prototype.isEmpty = function()
{
	var place = this.getContainer();
	return place && place.firstChild == null;
};

Story.prototype.search = function(text,useCaseSensitive,useRegExp)
{
	this.closeAllTiddlers();
	highlightHack = new RegExp(useRegExp ? text : text.escapeRegExp(),useCaseSensitive ? "mg" : "img");
	var matches = store.search(highlightHack,"title","excludeSearch");
	this.displayTiddlers(null,matches);
	highlightHack = null;
	var q = useRegExp ? "/" : "'";
	if(matches.length > 0)
		displayMessage(config.macros.search.successMsg.format([matches.length.toString(),q + text + q]));
	else
		displayMessage(config.macros.search.failureMsg.format([q + text + q]));
};

Story.prototype.findContainingTiddler = function(e)
{
	while(e && !hasClass(e,"tiddler"))
		e = e.parentNode;
	return e;
};

Story.prototype.gatherSaveFields = function(e,fields)
{
	if(e && e.getAttribute) {
		var f = e.getAttribute("edit");
		if(f)
			fields[f] = e.value.replace(/\r/mg,"");
		if(e.hasChildNodes()) {
			var c = e.childNodes;
			for(var t=0; t<c.length; t++)
				this.gatherSaveFields(c[t],fields);
		}
	}
};

Story.prototype.hasChanges = function(title)
{
	var e = this.getTiddler(title);
	if(e) {
		var fields = {};
		this.gatherSaveFields(e,fields);
		if(store.fetchTiddler(title)) {
			for(var n in fields) {
				if(store.getValue(title,n) != fields[n]) //# tiddler changed
					return true;
			}
		} else {
			if(store.isShadowTiddler(title) && store.getShadowTiddlerText(title) == fields.text) { //# not checking for title or tags
				return false;
			} else { //# changed shadow or new tiddler
				return true;
			}
		}
	}
	return false;
};

Story.prototype.saveTiddler = function(title,minorUpdate)
{
	var tiddlerElem = this.getTiddler(title);
	if(tiddlerElem) {
		var fields = {};
		this.gatherSaveFields(tiddlerElem,fields);
		var newTitle = fields.title || title;
		if(!store.tiddlerExists(newTitle))
			newTitle = newTitle.trim();
		if(store.tiddlerExists(newTitle) && newTitle != title) {
			if(!confirm(config.messages.overwriteWarning.format([newTitle.toString()])))
				return null;
		}
		if(newTitle != title)
			this.closeTiddler(newTitle,false);
		tiddlerElem.id = this.tiddlerId(newTitle);
		tiddlerElem.setAttribute("tiddler",newTitle);
		tiddlerElem.setAttribute("template",DEFAULT_VIEW_TEMPLATE);
		tiddlerElem.setAttribute("dirty","false");
		if(config.options.chkForceMinorUpdate)
			minorUpdate = !minorUpdate;
		if(!store.tiddlerExists(newTitle))
			minorUpdate = false;
		var newDate = new Date();
		if(store.tiddlerExists(title)) {
			var extendedFields = store.fetchTiddler(title).fields;
		} else {
			extendedFields = merge({},config.defaultCustomFields);
		}
		for(var n in fields) {
			if(!TiddlyWiki.isStandardField(n))
				extendedFields[n] = fields[n];
		}
		var tiddler = store.saveTiddler(title,newTitle,fields.text,minorUpdate ? undefined : config.options.txtUserName,minorUpdate ? undefined : newDate,fields.tags,extendedFields);
		autoSaveChanges(null,[tiddler]);
		return newTitle;
	}
	return null;
};

Story.prototype.permaView = function()
{
	var links = [];
	this.forEachTiddler(function(title,element) {
		links.push(String.encodeTiddlyLink(title));
	});
	var t = encodeURIComponent(links.join(" "));
	if(t == "")
		t = "#";
	if(window.location.hash != t)
		window.location.hash = t;
};

Story.prototype.switchTheme = function(theme)
{
	if(safeMode)
		return;

	var isAvailable = function(title) {
		var s = title ? title.indexOf(config.textPrimitives.sectionSeparator) : -1;
		if(s!=-1)
			title = title.substr(0,s);
		return store.tiddlerExists(title) || store.isShadowTiddler(title);
	};

	var getSlice = function(theme,slice) {
		var r;
		if(readOnly)
			r = store.getTiddlerSlice(theme,slice+"ReadOnly") || store.getTiddlerSlice(theme,"Web"+slice);
		r = r || store.getTiddlerSlice(theme,slice);
		if(r && r.indexOf(config.textPrimitives.sectionSeparator)==0)
			r = theme + r;
		return isAvailable(r) ? r : slice;
	};

	var replaceNotification = function(i,name,theme,slice) {
		var newName = getSlice(theme,slice);
		if(name!=newName && store.namedNotifications[i].name==name) {
			store.namedNotifications[i].name = newName;
			return newName;
		}
		return name;
	};

	var pt = config.refresherData.pageTemplate;
	var vi = DEFAULT_VIEW_TEMPLATE;
	var vt = config.tiddlerTemplates[vi];
	var ei = DEFAULT_EDIT_TEMPLATE;
	var et = config.tiddlerTemplates[ei];

	for(var i=0; i<config.notifyTiddlers.length; i++) {
		var name = config.notifyTiddlers[i].name;
		switch(name) {
		case "PageTemplate":
			config.refresherData.pageTemplate = replaceNotification(i,config.refresherData.pageTemplate,theme,name);
			break;
		case "StyleSheet":
			removeStyleSheet(config.refresherData.styleSheet);
			config.refresherData.styleSheet = replaceNotification(i,config.refresherData.styleSheet,theme,name);
			break;
		case "ColorPalette":
			config.refresherData.colorPalette = replaceNotification(i,config.refresherData.colorPalette,theme,name);
			break;
		default:
			break;
		}
	}
	config.tiddlerTemplates[vi] = getSlice(theme,"ViewTemplate");
	config.tiddlerTemplates[ei] = getSlice(theme,"EditTemplate");
	if(!startingUp) {
		if(config.refresherData.pageTemplate!=pt || config.tiddlerTemplates[vi]!=vt || config.tiddlerTemplates[ei]!=et) {
			refreshAll();
			this.refreshAllTiddlers(true);
		} else {
			setStylesheet(store.getRecursiveTiddlerText(config.refresherData.styleSheet,"",10),config.refreshers.styleSheet);
		}
		config.options.txtTheme = theme;
		saveOptionCookie("txtTheme");
	}
};

//--
//-- Backstage
//--

var backstage = {
	area: null,
	toolbar: null,
	button: null,
	showButton: null,
	hideButton: null,
	cloak: null,
	panel: null,
	panelBody: null,
	panelFooter: null,
	currTabName: null,
	currTabElem: null,
	content: null,

	init: function() {
		var cmb = config.messages.backstage;
		this.area = document.getElementById("backstageArea");
		this.toolbar = document.getElementById("backstageToolbar");
		this.button = document.getElementById("backstageButton");
		this.button.style.display = "block";
		var t = cmb.open.text + " " + glyph("bentArrowLeft");
		this.showButton = createTiddlyButton(this.button,t,cmb.open.tooltip,
						function(e) {backstage.show(); return false;},null,"backstageShow");
		t = glyph("bentArrowRight") + " " + cmb.close.text;
		this.hideButton = createTiddlyButton(this.button,t,cmb.close.tooltip,
						function(e) {backstage.hide(); return false;},null,"backstageHide");
		this.cloak = document.getElementById("backstageCloak");
		this.panel = document.getElementById("backstagePanel");
		this.panelFooter = createTiddlyElement(this.panel,"div",null,"backstagePanelFooter");
		this.panelBody = createTiddlyElement(this.panel,"div",null,"backstagePanelBody");
		this.cloak.onmousedown = function(e) {backstage.switchTab(null);};
		createTiddlyText(this.toolbar,cmb.prompt);
		for(t=0; t<config.backstageTasks.length; t++) {
			var taskName = config.backstageTasks[t];
			var task = config.tasks[taskName];
			var handler = task.action ? this.onClickCommand : this.onClickTab;
			var text = task.text + (task.action ? "" : glyph("downTriangle"));
			var btn = createTiddlyButton(this.toolbar,text,task.tooltip,handler,"backstageTab");
			addClass(btn,task.action ? "backstageAction" : "backstageTask");
			btn.setAttribute("task", taskName);
			}
		this.content = document.getElementById("contentWrapper");
		if(config.options.chkBackstage)
			this.show();
		else
			this.hide();
	},

	isVisible: function() {
		return this.area ? this.area.style.display == "block" : false;
	},

	show: function() {
		this.area.style.display = "block";
		if(anim && config.options.chkAnimate) {
			backstage.toolbar.style.left = findWindowWidth() + "px";
			var p = [{style: "left", start: findWindowWidth(), end: 0, template: "%0px"}];
			anim.startAnimating(new Morpher(backstage.toolbar,config.animDuration,p));
		} else {
			backstage.area.style.left = "0px";
		}
		jQuery(this.showButton).hide();
		jQuery(this.hideButton).show();
		config.options.chkBackstage = true;
		saveOptionCookie("chkBackstage");
		addClass(this.content,"backstageVisible");
	},

	hide: function() {
		if(this.currTabElem) {
			this.switchTab(null);
		} else {
			backstage.toolbar.style.left = "0px";
			if(anim && config.options.chkAnimate) {
				var p = [{style: "left", start: 0, end: findWindowWidth(), template: "%0px"}];
				var c = function(element,properties) {backstage.area.style.display = "none";};
				anim.startAnimating(new Morpher(backstage.toolbar,config.animDuration,p,c));
			} else {
				this.area.style.display = "none";
			}
			this.showButton.style.display = "block";
			this.hideButton.style.display = "none";
			config.options.chkBackstage = false;
			saveOptionCookie("chkBackstage");
			removeClass(this.content, "backstageVisible");
		}
	},

	onClickCommand: function(e) {
		var task = config.tasks[this.getAttribute("task")];
		displayMessage(task);
		if(task.action) {
			backstage.switchTab(null);
			task.action();
		}
		return false;
	},

	onClickTab: function(e) {
		backstage.switchTab(this.getAttribute("task"));
		return false;
	},

	// Switch to a given tab, or none if null is passed
	switchTab: function(tabName) {
		var tabElem = null;
		var e = this.toolbar.firstChild;
		while(e)
			{
			if(e.getAttribute && e.getAttribute("task") == tabName)
				tabElem = e;
			e = e.nextSibling;
			}
		if(tabName == backstage.currTabName) {
			backstage.hidePanel();
			return;
		}
		if(backstage.currTabElem) {
			removeClass(this.currTabElem, "backstageSelTab");
		}
		if(tabElem && tabName) {
			backstage.preparePanel();
			addClass(tabElem,"backstageSelTab");
			var task = config.tasks[tabName];
			wikify(task.content,backstage.panelBody,null,null);
			backstage.showPanel();
		} else if(backstage.currTabElem) {
			backstage.hidePanel();
		}
		backstage.currTabName = tabName;
		backstage.currTabElem = tabElem;
	},

	isPanelVisible: function() {
		return backstage.panel ? backstage.panel.style.display == "block" : false;
	},

	preparePanel: function() {
		backstage.cloak.style.height = findWindowHeight() + "px";
		backstage.cloak.style.display = "block";
		removeChildren(backstage.panelBody);
		return backstage.panelBody;
	},

	showPanel: function() {
		backstage.panel.style.display = "block";
		if(anim && config.options.chkAnimate) {
			backstage.panel.style.top = (-backstage.panel.offsetHeight) + "px";
			var p = [{style: "top", start: -backstage.panel.offsetHeight, end: 0, template: "%0px"}];
			anim.startAnimating(new Morpher(backstage.panel,config.animDuration,p),new Scroller(backstage.panel,false));
		} else {
			backstage.panel.style.top = "0px";
		}
		return backstage.panelBody;
	},

	hidePanel: function() {
		if(backstage.currTabElem)
			removeClass(backstage.currTabElem, "backstageSelTab");
		backstage.currTabElem = null;
		backstage.currTabName = null;
		if(anim && config.options.chkAnimate) {
			var p = [
				{style: "top", start: 0, end: -(backstage.panel.offsetHeight), template: "%0px"},
				{style: "display", atEnd: "none"}
			];
			var c = function(element,properties) {backstage.cloak.style.display = "none";};
			anim.startAnimating(new Morpher(backstage.panel,config.animDuration,p,c));
		} else {
			jQuery([backstage.panel,backstage.cloak]).hide();
		}
	}
};

config.macros.backstage = {};

config.macros.backstage.handler = function(place,macroName,params)
{
	var backstageTask = config.tasks[params[0]];
	if(backstageTask)
		createTiddlyButton(place,backstageTask.text,backstageTask.tooltip,function(e) {backstage.switchTab(params[0]); return false;});
};

//--
//-- ImportTiddlers macro
//--

config.macros.importTiddlers.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	if(readOnly) {
		createTiddlyElement(place,"div",null,"marked",this.readOnlyWarning);
		return;
	}
	var w = new Wizard();
	w.createWizard(place,this.wizardTitle);
	this.restart(w);
};

config.macros.importTiddlers.onCancel = function(e)
{
	var wizard = new Wizard(this);
	var place = wizard.clear();
	config.macros.importTiddlers.restart(wizard);
	return false;
};

config.macros.importTiddlers.onClose = function(e)
{
	backstage.hidePanel();
	return false;
};

config.macros.importTiddlers.restart = function(wizard)
{
	wizard.addStep(this.step1Title,this.step1Html);
	var s = wizard.getElement("selTypes");
	for(var t in config.adaptors) {
		var e = createTiddlyElement(s,"option",null,null,config.adaptors[t].serverLabel ? config.adaptors[t].serverLabel : t);
		e.value = t;
	}
	if(config.defaultAdaptor)
		s.value = config.defaultAdaptor;
	s = wizard.getElement("selFeeds");
	var feeds = this.getFeeds();
	for(t in feeds) {
		e = createTiddlyElement(s,"option",null,null,t);
		e.value = t;
	}
	wizard.setValue("feeds",feeds);
	s.onchange = config.macros.importTiddlers.onFeedChange;
	var fileInput = wizard.getElement("txtBrowse");
	fileInput.onchange = config.macros.importTiddlers.onBrowseChange;
	fileInput.onkeyup = config.macros.importTiddlers.onBrowseChange;
	wizard.setButtons([{caption: this.openLabel, tooltip: this.openPrompt, onClick: config.macros.importTiddlers.onOpen}]);
	wizard.formElem.action = "javascript:;";
	wizard.formElem.onsubmit = function() {
		if(!this.txtPath || this.txtPath.value.length) //# check for manually entered path in first step
			this.lastChild.firstChild.onclick();
	};
};

config.macros.importTiddlers.getFeeds = function()
{
	var feeds = {};
	var tagged = store.getTaggedTiddlers("systemServer","title");
	for(var t=0; t<tagged.length; t++) {
		var title = tagged[t].title;
		var serverType = store.getTiddlerSlice(title,"Type");
		if(!serverType)
			serverType = "file";
		feeds[title] = {title: title,
						url: store.getTiddlerSlice(title,"URL"),
						workspace: store.getTiddlerSlice(title,"Workspace"),
						workspaceList: store.getTiddlerSlice(title,"WorkspaceList"),
						tiddlerFilter: store.getTiddlerSlice(title,"TiddlerFilter"),
						serverType: serverType,
						description: store.getTiddlerSlice(title,"Description")};
	}
	return feeds;
};

config.macros.importTiddlers.onFeedChange = function(e)
{
	var wizard = new Wizard(this);
	var selTypes = wizard.getElement("selTypes");
	var fileInput = wizard.getElement("txtPath");
	var feeds = wizard.getValue("feeds");
	var f = feeds[this.value];
	if(f) {
		selTypes.value = f.serverType;
		fileInput.value = f.url;
		wizard.setValue("feedName",f.serverType);
		wizard.setValue("feedHost",f.url);
		wizard.setValue("feedWorkspace",f.workspace);
		wizard.setValue("feedWorkspaceList",f.workspaceList);
		wizard.setValue("feedTiddlerFilter",f.tiddlerFilter);
	}
	return false;
};

config.macros.importTiddlers.onBrowseChange = function(e)
{
	var wizard = new Wizard(this);
	var fileInput = wizard.getElement("txtPath");
	fileInput.value = config.macros.importTiddlers.getURLFromLocalPath(this.value);
	var serverType = wizard.getElement("selTypes");
	serverType.value = "file";
	return true;
};

config.macros.importTiddlers.getURLFromLocalPath = function(v)
{
	if(!v||!v.length)
		return v;
	v = v.replace(/\\/g,"/"); // use "/" for cross-platform consistency
	var u;
	var t = v.split(":");
	var p = t[1]||t[0]; // remove drive letter (if any)
	if (t[1] && (t[0]=="http"||t[0]=="https"||t[0]=="file")) {
		u = v;
	} else if(p.substr(0,1)=="/") {
		u = document.location.protocol + "//" + document.location.hostname + (t[1] ? "/" : "") + v;
	} else {
		var c = document.location.href.replace(/\\/g,"/");
		var pos = c.lastIndexOf("/");
		if (pos!=-1)
			c = c.substr(0,pos); // remove filename
		u = c + "/" + p;
	}
	return u;
};

config.macros.importTiddlers.onOpen = function(e)
{
	var wizard = new Wizard(this);
	var fileInput = wizard.getElement("txtPath");
	var url = fileInput.value;
	var serverType = wizard.getElement("selTypes").value || config.defaultAdaptor;
	var adaptor = new config.adaptors[serverType]();
	wizard.setValue("adaptor",adaptor);
	wizard.setValue("serverType",serverType);
	wizard.setValue("host",url);
	var ret = adaptor.openHost(url,null,wizard,config.macros.importTiddlers.onOpenHost);
	if(ret !== true)
		displayMessage(ret);
	wizard.setButtons([{caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel}],config.macros.importTiddlers.statusOpenHost);
	return false;
};

config.macros.importTiddlers.onOpenHost = function(context,wizard)
{
	var adaptor = wizard.getValue("adaptor");
	if(context.status !== true)
		displayMessage("Error in importTiddlers.onOpenHost: " + context.statusText);
	var ret = adaptor.getWorkspaceList(context,wizard,config.macros.importTiddlers.onGetWorkspaceList);
	if(ret !== true)
		displayMessage(ret);
	wizard.setButtons([{caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel}],config.macros.importTiddlers.statusGetWorkspaceList);
};

config.macros.importTiddlers.onGetWorkspaceList = function(context,wizard)
{
	if(context.status !== true)
		displayMessage("Error in importTiddlers.onGetWorkspaceList: " + context.statusText);
	wizard.setValue("context",context);
	var workspace = wizard.getValue("feedWorkspace");
	if(!workspace && context.workspaces.length==1)
		workspace = context.workspaces[0].title;
	if(workspace) {
		var ret = context.adaptor.openWorkspace(workspace,context,wizard,config.macros.importTiddlers.onOpenWorkspace);
		if(ret !== true)
			displayMessage(ret);
		wizard.setValue("workspace",workspace);
		wizard.setButtons([{caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel}],config.macros.importTiddlers.statusOpenWorkspace);
		return;
	}
	wizard.addStep(config.macros.importTiddlers.step2Title,config.macros.importTiddlers.step2Html);
	var s = wizard.getElement("selWorkspace");
	s.onchange = config.macros.importTiddlers.onWorkspaceChange;
	for(var t=0; t<context.workspaces.length; t++) {
		var e = createTiddlyElement(s,"option",null,null,context.workspaces[t].title);
		e.value = context.workspaces[t].title;
	}
	var workspaceList = wizard.getValue("feedWorkspaceList");
	if(workspaceList) {
		var list = workspaceList.parseParams("workspace",null,false,true);
		for(var n=1; n<list.length; n++) {
			if(context.workspaces.findByField("title",list[n].value) == null) {
				e = createTiddlyElement(s,"option",null,null,list[n].value);
				e.value = list[n].value;
			}
		}
	}
	if(workspace) {
		t = wizard.getElement("txtWorkspace");
		t.value = workspace;
	}
	wizard.setButtons([{caption: config.macros.importTiddlers.openLabel, tooltip: config.macros.importTiddlers.openPrompt, onClick: config.macros.importTiddlers.onChooseWorkspace}]);
};

config.macros.importTiddlers.onWorkspaceChange = function(e)
{
	var wizard = new Wizard(this);
	var t = wizard.getElement("txtWorkspace");
	t.value = this.value;
	this.selectedIndex = 0;
	return false;
};

config.macros.importTiddlers.onChooseWorkspace = function(e)
{
	var wizard = new Wizard(this);
	var adaptor = wizard.getValue("adaptor");
	var workspace = wizard.getElement("txtWorkspace").value;
	wizard.setValue("workspace",workspace);
	var context = wizard.getValue("context");
	var ret = adaptor.openWorkspace(workspace,context,wizard,config.macros.importTiddlers.onOpenWorkspace);
	if(ret !== true)
		displayMessage(ret);
	wizard.setButtons([{caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel}],config.macros.importTiddlers.statusOpenWorkspace);
	return false;
};

config.macros.importTiddlers.onOpenWorkspace = function(context,wizard)
{
	if(context.status !== true)
		displayMessage("Error in importTiddlers.onOpenWorkspace: " + context.statusText);
	var adaptor = wizard.getValue("adaptor");
	var ret = adaptor.getTiddlerList(context,wizard,config.macros.importTiddlers.onGetTiddlerList,wizard.getValue("feedTiddlerFilter"));
	if(ret !== true)
		displayMessage(ret);
	wizard.setButtons([{caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel}],config.macros.importTiddlers.statusGetTiddlerList);
};

config.macros.importTiddlers.onGetTiddlerList = function(context,wizard)
{
	if(context.status !== true) {
		wizard.setButtons([{caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel}],config.macros.importTiddlers.errorGettingTiddlerList);
		return;
	}
	// Extract data for the listview
	var listedTiddlers = [];
	if(context.tiddlers) {
		for(var n=0; n<context.tiddlers.length; n++) {
			var tiddler = context.tiddlers[n];
			listedTiddlers.push({
				title: tiddler.title,
				modified: tiddler.modified,
				modifier: tiddler.modifier,
				text: tiddler.text ? wikifyPlainText(tiddler.text,100) : "",
				tags: tiddler.tags,
				size: tiddler.text ? tiddler.text.length : 0,
				tiddler: tiddler
			});
		}
	}
	listedTiddlers.sort(function(a,b) {return a.title < b.title ? -1 : (a.title == b.title ? 0 : +1);});
	// Display the listview
	wizard.addStep(config.macros.importTiddlers.step3Title,config.macros.importTiddlers.step3Html);
	var markList = wizard.getElement("markList");
	var listWrapper = document.createElement("div");
	markList.parentNode.insertBefore(listWrapper,markList);
	var listView = ListView.create(listWrapper,listedTiddlers,config.macros.importTiddlers.listViewTemplate);
	wizard.setValue("listView",listView);
	wizard.setValue("context",context);
	var txtSaveTiddler = wizard.getElement("txtSaveTiddler");
	txtSaveTiddler.value = config.macros.importTiddlers.generateSystemServerName(wizard);
	wizard.setButtons([
			{caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel},
			{caption: config.macros.importTiddlers.importLabel, tooltip: config.macros.importTiddlers.importPrompt, onClick: config.macros.importTiddlers.doImport}
		]);
};

config.macros.importTiddlers.generateSystemServerName = function(wizard)
{
	var serverType = wizard.getValue("serverType");
	var host = wizard.getValue("host");
	var workspace = wizard.getValue("workspace");
	var pattern = config.macros.importTiddlers[workspace ? "systemServerNamePattern" : "systemServerNamePatternNoWorkspace"];
	return pattern.format([serverType,host,workspace]);
};

config.macros.importTiddlers.saveServerTiddler = function(wizard)
{
	var txtSaveTiddler = wizard.getElement("txtSaveTiddler").value;
	if(store.tiddlerExists(txtSaveTiddler)) {
		if(!confirm(config.macros.importTiddlers.confirmOverwriteSaveTiddler.format([txtSaveTiddler])))
			return;
		store.suspendNotifications();
		store.removeTiddler(txtSaveTiddler);
		store.resumeNotifications();
	}
	var serverType = wizard.getValue("serverType");
	var host = wizard.getValue("host");
	var workspace = wizard.getValue("workspace");
	var text = config.macros.importTiddlers.serverSaveTemplate.format([serverType,host,workspace]);
	store.saveTiddler(txtSaveTiddler,txtSaveTiddler,text,config.macros.importTiddlers.serverSaveModifier,new Date(),["systemServer"]);
};

config.macros.importTiddlers.doImport = function(e)
{
	var wizard = new Wizard(this);
	if(wizard.getElement("chkSave").checked)
		config.macros.importTiddlers.saveServerTiddler(wizard);
	var chkSync = wizard.getElement("chkSync").checked;
	wizard.setValue("sync",chkSync);
	var listView = wizard.getValue("listView");
	var rowNames = ListView.getSelectedRows(listView);
	var adaptor = wizard.getValue("adaptor");
	var overwrite = [];
	var t;
	for(t=0; t<rowNames.length; t++) {
		if(store.tiddlerExists(rowNames[t]))
			overwrite.push(rowNames[t]);
	}
	if(overwrite.length > 0) {
		if(!confirm(config.macros.importTiddlers.confirmOverwriteText.format([overwrite.join(", ")])))
			return false;
	}
	wizard.addStep(config.macros.importTiddlers.step4Title.format([rowNames.length]),config.macros.importTiddlers.step4Html);
	for(t=0; t<rowNames.length; t++) {
		var link = document.createElement("div");
		createTiddlyLink(link,rowNames[t],true);
		var place = wizard.getElement("markReport");
		place.parentNode.insertBefore(link,place);
	}
	wizard.setValue("remainingImports",rowNames.length);
	wizard.setButtons([
			{caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel}
		],config.macros.importTiddlers.statusDoingImport);
	var wizardContext = wizard.getValue("context");
	var tiddlers = wizardContext ? wizardContext.tiddlers : [];
	for(t=0; t<rowNames.length; t++) {
		var context = {
			allowSynchronous:true,
			tiddler:tiddlers[tiddlers.findByField("title",rowNames[t])]
		};
		adaptor.getTiddler(rowNames[t],context,wizard,config.macros.importTiddlers.onGetTiddler);
	}
	return false;
};

config.macros.importTiddlers.onGetTiddler = function(context,wizard)
{
	if(!context.status)
		displayMessage("Error in importTiddlers.onGetTiddler: " + context.statusText);
	var tiddler = context.tiddler;
	store.suspendNotifications();
	store.saveTiddler(tiddler.title, tiddler.title, tiddler.text, tiddler.modifier, tiddler.modified, tiddler.tags, tiddler.fields, true, tiddler.created);
	if(!wizard.getValue("sync")) {
		store.setValue(tiddler.title,'server',null);
	}
	store.resumeNotifications();
	if(!context.isSynchronous)
		store.notify(tiddler.title,true);
	var remainingImports = wizard.getValue("remainingImports")-1;
	wizard.setValue("remainingImports",remainingImports);
	if(remainingImports == 0) {
		if(context.isSynchronous) {
			store.notifyAll();
			refreshDisplay();
		}
		wizard.setButtons([
				{caption: config.macros.importTiddlers.doneLabel, tooltip: config.macros.importTiddlers.donePrompt, onClick: config.macros.importTiddlers.onClose}
			],config.macros.importTiddlers.statusDoneImport);
		autoSaveChanges();
	}
};

//--
//-- Upgrade macro
//--

config.macros.upgrade.handler = function(place)
{
	var w = new Wizard();
	w.createWizard(place,this.wizardTitle);
	w.addStep(this.step1Title,this.step1Html.format([this.source,this.source]));
	w.setButtons([{caption: this.upgradeLabel, tooltip: this.upgradePrompt, onClick: this.onClickUpgrade}]);
};

config.macros.upgrade.onClickUpgrade = function(e)
{
	var me = config.macros.upgrade;
	var w = new Wizard(this);
	if(window.location.protocol != "file:") {
		alert(me.errorCantUpgrade);
		return false;
	}
	if(story.areAnyDirty() || store.isDirty()) {
		alert(me.errorNotSaved);
		return false;
	}
	var localPath = getLocalPath(document.location.toString());
	var backupPath = getBackupPath(localPath,me.backupExtension);
	w.setValue("backupPath",backupPath);
	w.setButtons([],me.statusPreparingBackup);
	var original = loadOriginal(localPath);
	w.setButtons([],me.statusSavingBackup);
	var backup = copyFile(backupPath,localPath);
	if(!backup)
		backup = saveFile(backupPath,original);
	if(!backup) {
		w.setButtons([],me.errorSavingBackup);
		alert(me.errorSavingBackup);
		return false;
	}
	w.setButtons([],me.statusLoadingCore);
	var load = loadRemoteFile(me.source,me.onLoadCore,w);
	if(typeof load == "string") {
		w.setButtons([],me.errorLoadingCore);
		alert(me.errorLoadingCore);
		return false;
	}
	return false;
};

config.macros.upgrade.onLoadCore = function(status,params,responseText,url,xhr)
{
	var me = config.macros.upgrade;
	var w = params;
	var errMsg;
	if(!status)
		errMsg = me.errorLoadingCore;
	var newVer = me.extractVersion(responseText);
	if(!newVer)
		errMsg = me.errorCoreFormat;
	if(errMsg) {
		w.setButtons([],errMsg);
		alert(errMsg);
		return;
	}
	var onStartUpgrade = function(e) {
		w.setButtons([],me.statusSavingCore);
		var localPath = getLocalPath(document.location.toString());
		saveFile(localPath,responseText);
		w.setButtons([],me.statusReloadingCore);
		var backupPath = w.getValue("backupPath");
		var newLoc = document.location.toString() + "?time=" + new Date().convertToYYYYMMDDHHMM() + "#upgrade:[[" + encodeURI(backupPath) + "]]";
		window.setTimeout(function () {window.location = newLoc;},10);
	};
	var step2 = [me.step2Html_downgrade,me.step2Html_restore,me.step2Html_upgrade][compareVersions(version,newVer) + 1];
	w.addStep(me.step2Title,step2.format([formatVersion(newVer),formatVersion(version)]));
	w.setButtons([{caption: me.startLabel, tooltip: me.startPrompt, onClick: onStartUpgrade},{caption: me.cancelLabel, tooltip: me.cancelPrompt, onClick: me.onCancel}]);
};

config.macros.upgrade.onCancel = function(e)
{
	var me = config.macros.upgrade;
	var w = new Wizard(this);
	w.addStep(me.step3Title,me.step3Html);
	w.setButtons([]);
	return false;
};

config.macros.upgrade.extractVersion = function(upgradeFile)
{
	var re = /^var version = \{title: "([^"]+)", major: (\d+), minor: (\d+), revision: (\d+)(, beta: (\d+)){0,1}, date: new Date\("([^"]+)"\)/mg;
	var m = re.exec(upgradeFile);
	return  m ? {title: m[1], major: m[2], minor: m[3], revision: m[4], beta: m[6], date: new Date(m[7])} : null;
};

function upgradeFrom(path)
{
	var importStore = new TiddlyWiki();
	var tw = loadFile(path);
	if(window.netscape !== undefined)
		tw = convertUTF8ToUnicode(tw);
	importStore.importTiddlyWiki(tw);
	importStore.forEachTiddler(function(title,tiddler) {
		if(!store.getTiddler(title)) {
			store.addTiddler(tiddler);
		}
	});
	refreshDisplay();
	saveChanges(); //# To create appropriate Markup* sections
	alert(config.messages.upgradeDone.format([formatVersion()]));
	window.location = window.location.toString().substr(0,window.location.toString().lastIndexOf("?"));
}

//--
//-- Sync macro
//--

// Synchronisation handlers
config.syncers = {};

// Sync state.
var currSync = null;

// sync macro
config.macros.sync.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	if(!wikifier.isStatic)
		this.startSync(place);
};

config.macros.sync.cancelSync = function()
{
	currSync = null;
};

config.macros.sync.startSync = function(place)
{
	if(currSync)
		config.macros.sync.cancelSync();
	currSync = {};
	currSync.syncList = this.getSyncableTiddlers();
	currSync.syncTasks = this.createSyncTasks(currSync.syncList);
	this.preProcessSyncableTiddlers(currSync.syncList);
	var wizard = new Wizard();
	currSync.wizard = wizard;
	wizard.createWizard(place,this.wizardTitle);
	wizard.addStep(this.step1Title,this.step1Html);
	var markList = wizard.getElement("markList");
	var listWrapper = document.createElement("div");
	markList.parentNode.insertBefore(listWrapper,markList);
	currSync.listView = ListView.create(listWrapper,currSync.syncList,this.listViewTemplate);
	this.processSyncableTiddlers(currSync.syncList);
	wizard.setButtons([{caption: this.syncLabel, tooltip: this.syncPrompt, onClick: this.doSync}]);
};

config.macros.sync.getSyncableTiddlers = function()
{
	var list = [];
	store.forEachTiddler(function(title,tiddler) {
		var syncItem = {};
		syncItem.serverType = tiddler.getServerType();
		syncItem.serverHost = tiddler.fields['server.host'];
		if(syncItem.serverType && syncItem.serverHost) {
			syncItem.adaptor = new config.adaptors[syncItem.serverType];
			syncItem.serverWorkspace = tiddler.fields['server.workspace'];
			syncItem.tiddler = tiddler;
			syncItem.title = tiddler.title;
			syncItem.isTouched = tiddler.isTouched();
			syncItem.selected = syncItem.isTouched;
			syncItem.syncStatus = config.macros.sync.syncStatusList[syncItem.isTouched ? "changedLocally" : "none"];
			syncItem.status = syncItem.syncStatus.text;
			list.push(syncItem);
		}
		});
	list.sort(function(a,b) {return a.title < b.title ? -1 : (a.title == b.title ? 0 : +1);});
	return list;
};

config.macros.sync.preProcessSyncableTiddlers = function(syncList)
{
	for(var i=0; i<syncList.length; i++) {
		var si = syncList[i];
		si.serverUrl = si.adaptor.generateTiddlerInfo(si.tiddler).uri;
	}
};

config.macros.sync.processSyncableTiddlers = function(syncList)
{
	for(var i=0; i<syncList.length; i++) {
		var si = syncList[i];
		if(si.syncStatus.display)
			si.rowElement.style.display = si.syncStatus.display;
		if(si.syncStatus.className)
			si.rowElement.className = si.syncStatus.className;
	}
};

config.macros.sync.createSyncTasks = function(syncList)
{
	var syncTasks = [];
	for(var i=0; i<syncList.length; i++) {
		var si = syncList[i];
		var r = null;
		for(var j=0; j<syncTasks.length; j++) {
			var cst = syncTasks[j];
			if(si.serverType == cst.serverType && si.serverHost == cst.serverHost && si.serverWorkspace == cst.serverWorkspace)
				r = cst;
		}
		if(r) {
			si.syncTask = r;
			r.syncItems.push(si);
		} else {
			si.syncTask = this.createSyncTask(si);
			syncTasks.push(si.syncTask);
		}
	}
	return syncTasks;
};

config.macros.sync.createSyncTask = function(syncItem)
{
	var st = {};
	st.serverType = syncItem.serverType;
	st.serverHost = syncItem.serverHost;
	st.serverWorkspace = syncItem.serverWorkspace;
	st.syncItems = [syncItem];

	var openWorkspaceCallback = function(context,syncItems) {
		if(context.status) {
			context.adaptor.getTiddlerList(context,syncItems,getTiddlerListCallback);
			return true;
		}
		displayMessage(context.statusText);
		return false;
	};

	var getTiddlerListCallback = function(context,sycnItems) {
		if(!context.status) {
			displayMessage(context.statusText);
			return false;
		}
		syncItems = context.userParams;
		var tiddlers = context.tiddlers;
		for(var i=0; i<syncItems.length; i++) {
			var si = syncItems[i];
			var f = tiddlers.findByField("title",si.title);
			if(f !== null) {
				if(tiddlers[f].fields['server.page.revision'] > si.tiddler.fields['server.page.revision']) {
					si.syncStatus = config.macros.sync.syncStatusList[si.isTouched ? 'changedBoth' : 'changedServer'];
				}
			} else {
				si.syncStatus = config.macros.sync.syncStatusList.notFound;
			}
			config.macros.sync.updateSyncStatus(si);
		}
		return true;
	};
	var context = {host:st.serverHost,workspace:st.serverWorkspace};
	syncItem.adaptor.openHost(st.serverHost);
	syncItem.adaptor.openWorkspace(st.serverWorkspace,context,st.syncItems,openWorkspaceCallback);
	return st;
};

config.macros.sync.updateSyncStatus = function(syncItem)
{
	var e = syncItem.colElements["status"];
	removeChildren(e);
	createTiddlyText(e,syncItem.syncStatus.text);
	if(syncItem.syncStatus.display)
		syncItem.rowElement.style.display = syncItem.syncStatus.display;
	if(syncItem.syncStatus.className)
		syncItem.rowElement.className = syncItem.syncStatus.className;
};

config.macros.sync.doSync = function(e)
{
	var getTiddlerCallback = function(context,syncItem) {
		if(syncItem) {
			var tiddler = context.tiddler;
			store.saveTiddler(tiddler.title,tiddler.title,tiddler.text,tiddler.modifier,tiddler.modified,tiddler.tags,tiddler.fields,true,tiddler.created);
			syncItem.syncStatus = config.macros.sync.syncStatusList.gotFromServer;
			config.macros.sync.updateSyncStatus(syncItem);
		}
	};
	var putTiddlerCallback = function(context,syncItem) {
		if(syncItem) {
			store.resetTiddler(context.title);
			syncItem.syncStatus = config.macros.sync.syncStatusList.putToServer;
			config.macros.sync.updateSyncStatus(syncItem);
		}
	};

	var rowNames = ListView.getSelectedRows(currSync.listView);
	var sl = config.macros.sync.syncStatusList;
	for(var i=0; i<currSync.syncList.length; i++) {
		var si = currSync.syncList[i];
		if(rowNames.indexOf(si.title) != -1) {
			var errorMsg = "Error in doSync: ";
			try {
				var r = true;
				switch(si.syncStatus) {
				case sl.changedServer:
					r = si.adaptor.getTiddler(si.title,null,si,getTiddlerCallback);
					break;
				case sl.notFound:
				case sl.changedLocally:
				case sl.changedBoth:
					r = si.adaptor.putTiddler(si.tiddler,null,si,putTiddlerCallback);
					break;
				default:
					break;
				}
				if(!r)
					displayMessage(errorMsg + r);
			} catch(ex) {
				if(ex.name == "TypeError")
					displayMessage("sync operation unsupported: " + ex.message);
				else
					displayMessage(errorMsg + ex.message);
			}
		}
	}
	return false;
};

//--
//-- Manager UI for groups of tiddlers
//--

config.macros.plugins.handler = function(place,macroName,params,wikifier,paramString)
{
	var wizard = new Wizard();
	wizard.createWizard(place,this.wizardTitle);
	wizard.addStep(this.step1Title,this.step1Html);
	var markList = wizard.getElement("markList");
	var listWrapper = document.createElement("div");
	markList.parentNode.insertBefore(listWrapper,markList);
	listWrapper.setAttribute("refresh","macro");
	listWrapper.setAttribute("macroName","plugins");
	listWrapper.setAttribute("params",paramString);
	this.refresh(listWrapper,paramString);
};

config.macros.plugins.refresh = function(listWrapper,params)
{
	var wizard = new Wizard(listWrapper);
	var selectedRows = [];
	ListView.forEachSelector(listWrapper,function(e,rowName) {
			if(e.checked)
				selectedRows.push(e.getAttribute("rowName"));
		});
	removeChildren(listWrapper);
	params = params.parseParams("anon");
	var plugins = installedPlugins.slice(0);
	var t,tiddler,p;
	var configTiddlers = store.getTaggedTiddlers("systemConfig");
	for(t=0; t<configTiddlers.length; t++) {
		tiddler = configTiddlers[t];
		if(plugins.findByField("title",tiddler.title) == null) {
			p = getPluginInfo(tiddler);
			p.executed = false;
			p.log.splice(0,0,this.skippedText);
			plugins.push(p);
		}
	}
	for(t=0; t<plugins.length; t++) {
		p = plugins[t];
		p.size = p.tiddler.text ? p.tiddler.text.length : 0;
		p.forced = p.tiddler.isTagged("systemConfigForce");
		p.disabled = p.tiddler.isTagged("systemConfigDisable");
		p.Selected = selectedRows.indexOf(plugins[t].title) != -1;
	}
	if(plugins.length == 0) {
		createTiddlyElement(listWrapper,"em",null,null,this.noPluginText);
		wizard.setButtons([]);
	} else {
		var listView = ListView.create(listWrapper,plugins,this.listViewTemplate,this.onSelectCommand);
		wizard.setValue("listView",listView);
		wizard.setButtons([
				{caption: config.macros.plugins.removeLabel, tooltip: config.macros.plugins.removePrompt, onClick: config.macros.plugins.doRemoveTag},
				{caption: config.macros.plugins.deleteLabel, tooltip: config.macros.plugins.deletePrompt, onClick: config.macros.plugins.doDelete}
			]);
	}
};

config.macros.plugins.doRemoveTag = function(e)
{
	var wizard = new Wizard(this);
	var listView = wizard.getValue("listView");
	var rowNames = ListView.getSelectedRows(listView);
	if(rowNames.length == 0) {
		alert(config.messages.nothingSelected);
	} else {
		for(var t=0; t<rowNames.length; t++)
			store.setTiddlerTag(rowNames[t],false,"systemConfig");
	}
};

config.macros.plugins.doDelete = function(e)
{
	var wizard = new Wizard(this);
	var listView = wizard.getValue("listView");
	var rowNames = ListView.getSelectedRows(listView);
	if(rowNames.length == 0) {
		alert(config.messages.nothingSelected);
	} else {
		if(confirm(config.macros.plugins.confirmDeleteText.format([rowNames.join(", ")]))) {
			for(var t=0; t<rowNames.length; t++) {
				store.removeTiddler(rowNames[t]);
				story.closeTiddler(rowNames[t],true);
			}
		}
	}
};

//--
//-- Message area
//--

function getMessageDiv()
{
	var msgArea = document.getElementById("messageArea");
	if(!msgArea)
		return null;
	if(!msgArea.hasChildNodes())
		createTiddlyButton(createTiddlyElement(msgArea,"div",null,"messageToolbar"),
			config.messages.messageClose.text,
			config.messages.messageClose.tooltip,
			clearMessage);
	msgArea.style.display = "block";
	return createTiddlyElement(msgArea,"div");
}

function displayMessage(text,linkText)
{
	var e = getMessageDiv();
	if(!e) {
		alert(text);
		return;
	}
	if(linkText) {
		var link = createTiddlyElement(e,"a",null,null,text);
		link.href = linkText;
		link.target = "_blank";
	} else {
		e.appendChild(document.createTextNode(text));
	}
}

function clearMessage()
{
	var msgArea = document.getElementById("messageArea");
	if(msgArea) {
		removeChildren(msgArea);
		msgArea.style.display = "none";
	}
	return false;
}

//--
//-- Refresh mechanism
//--

config.notifyTiddlers = [
	{name: "StyleSheetLayout", notify: refreshStyles},
	{name: "StyleSheetColors", notify: refreshStyles},
	{name: "StyleSheet", notify: refreshStyles},
	{name: "StyleSheetPrint", notify: refreshStyles},
	{name: "PageTemplate", notify: refreshPageTemplate},
	{name: "SiteTitle", notify: refreshPageTitle},
	{name: "SiteSubtitle", notify: refreshPageTitle},
	{name: "ColorPalette", notify: refreshColorPalette},
	{name: null, notify: refreshDisplay}
];

config.refreshers = {
	link: function(e,changeList)
		{
		var title = e.getAttribute("tiddlyLink");
		refreshTiddlyLink(e,title);
		return true;
		},

	tiddler: function(e,changeList)
		{
		var title = e.getAttribute("tiddler");
		var template = e.getAttribute("template");
		if(changeList && changeList.indexOf(title) != -1 && !story.isDirty(title))
			story.refreshTiddler(title,template,true);
		else
			refreshElements(e,changeList);
		return true;
		},

	content: function(e,changeList)
		{
		var title = e.getAttribute("tiddler");
		var force = e.getAttribute("force");
		if(force != null || changeList == null || changeList.indexOf(title) != -1) {
			removeChildren(e);
			wikify(store.getTiddlerText(title,""),e,null,store.fetchTiddler(title));
			return true;
		} else
			return false;
		},

	macro: function(e,changeList)
		{
		var macro = e.getAttribute("macroName");
		var params = e.getAttribute("params");
		if(macro)
			macro = config.macros[macro];
		if(macro && macro.refresh)
			macro.refresh(e,params);
		return true;
		}
};

config.refresherData = {
	styleSheet: "StyleSheet",
	defaultStyleSheet: "StyleSheet",
	pageTemplate: "PageTemplate",
	defaultPageTemplate: "PageTemplate",
	colorPalette: "ColorPalette",
	defaultColorPalette: "ColorPalette"
};

function refreshElements(root,changeList)
{
	var nodes = root.childNodes;
	for(var c=0; c<nodes.length; c++) {
		var e = nodes[c], type = null;
		if(e.getAttribute && (e.tagName ? e.tagName != "IFRAME" : true))
			type = e.getAttribute("refresh");
		var refresher = config.refreshers[type];
		var refreshed = false;
		if(refresher != undefined)
			refreshed = refresher(e,changeList);
		if(e.hasChildNodes() && !refreshed)
			refreshElements(e,changeList);
	}
}

function applyHtmlMacros(root,tiddler)
{
	var e = root.firstChild;
	while(e) {
		var nextChild = e.nextSibling;
		if(e.getAttribute) {
			var macro = e.getAttribute("macro");
			if(macro) {
				e.removeAttribute("macro");
				var params = "";
				var p = macro.indexOf(" ");
				if(p != -1) {
					params = macro.substr(p+1);
					macro = macro.substr(0,p);
				}
				invokeMacro(e,macro,params,null,tiddler);
			}
		}
		if(e.hasChildNodes())
			applyHtmlMacros(e,tiddler);
		e = nextChild;
	}
}

function refreshPageTemplate(title)
{
	var stash = jQuery("<div/>").appendTo("body").hide()[0];
	var display = story.getContainer();
	var nodes,t;
	if(display) {
		nodes = display.childNodes;
		for(t=nodes.length-1; t>=0; t--)
			stash.appendChild(nodes[t]);
	}
	var wrapper = document.getElementById("contentWrapper");

	var isAvailable = function(title) {
		var s = title ? title.indexOf(config.textPrimitives.sectionSeparator) : -1;
		if(s!=-1)
			title = title.substr(0,s);
		return store.tiddlerExists(title) || store.isShadowTiddler(title);
	};
	if(!title || !isAvailable(title))
		title = config.refresherData.pageTemplate;
	if(!isAvailable(title))
		title = config.refresherData.defaultPageTemplate; //# this one is always avaialable
	wrapper.innerHTML = store.getRecursiveTiddlerText(title,null,10);
	applyHtmlMacros(wrapper);
	refreshElements(wrapper);
	display = story.getContainer();
	removeChildren(display);
	if(!display)
		display = createTiddlyElement(wrapper,"div",story.containerId());
	nodes = stash.childNodes;
	for(t=nodes.length-1; t>=0; t--)
		display.appendChild(nodes[t]);
	removeNode(stash);
}

function refreshDisplay(hint)
{
	if(typeof hint == "string")
		hint = [hint];
	var e = document.getElementById("contentWrapper");
	refreshElements(e,hint);
	if(backstage.isPanelVisible()) {
		e = document.getElementById("backstage");
		refreshElements(e,hint);
	}
}

function refreshPageTitle()
{
	document.title = getPageTitle();
}

function getPageTitle()
{
	var st = wikifyPlain("SiteTitle");
	var ss = wikifyPlain("SiteSubtitle");
	return st + ((st == "" || ss == "") ? "" : " - ") + ss;
}

function refreshStyles(title,doc)
{
	setStylesheet(title == null ? "" : store.getRecursiveTiddlerText(title,"",10),title,doc || document);
}

function refreshColorPalette(title)
{
	if(!startingUp)
		refreshAll();
}

function refreshAll()
{
	refreshPageTemplate();
	refreshDisplay();
	refreshStyles("StyleSheetLayout");
	refreshStyles("StyleSheetColors");
	refreshStyles(config.refresherData.styleSheet);
	refreshStyles("StyleSheetPrint");
}

//--
//-- Options stuff
//--

config.optionHandlers = {
	'txt': {
		get: function(name) {return encodeCookie(config.options[name].toString());},
		set: function(name,value) {config.options[name] = decodeCookie(value);}
	},
	'chk': {
		get: function(name) {return config.options[name] ? "true" : "false";},
		set: function(name,value) {config.options[name] = value == "true";}
	}
};

function loadOptionsCookie()
{
	if(safeMode)
		return;
	var cookies = document.cookie.split(";");
	for(var c=0; c<cookies.length; c++) {
		var p = cookies[c].indexOf("=");
		if(p != -1) {
			var name = cookies[c].substr(0,p).trim();
			var value = cookies[c].substr(p+1).trim();
			var optType = name.substr(0,3);
			if(config.optionHandlers[optType] && config.optionHandlers[optType].set)
				config.optionHandlers[optType].set(name,value);
		}
	}
}

function saveOptionCookie(name)
{
	if(safeMode)
		return;
	var c = name + "=";
	var optType = name.substr(0,3);
	if(config.optionHandlers[optType] && config.optionHandlers[optType].get)
		c += config.optionHandlers[optType].get(name);
	c += "; expires=Fri, 1 Jan 2038 12:00:00 UTC; path=/";
	document.cookie = c;
}

function removeCookie(name)
{
	document.cookie = name + "=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;";
}

function encodeCookie(s)
{
	return escape(convertUnicodeToHtmlEntities(s));
}

function decodeCookie(s)
{
	s = unescape(s);
	var re = /&#[0-9]{1,5};/g;
	return s.replace(re,function($0) {return String.fromCharCode(eval($0.replace(/[&#;]/g,"")));});
}


config.macros.option.genericCreate = function(place,type,opt,className,desc)
{
	var typeInfo = config.macros.option.types[type];
	var c = document.createElement(typeInfo.elementType);
	if(typeInfo.typeValue)
		c.setAttribute("type",typeInfo.typeValue);
	c[typeInfo.eventName] = typeInfo.onChange;
	c.setAttribute("option",opt);
	c.className = className || typeInfo.className;
	if(config.optionsDesc[opt])
		c.setAttribute("title",config.optionsDesc[opt]);
	place.appendChild(c);
	if(desc != "no")
		createTiddlyText(place,config.optionsDesc[opt] || opt);
	c[typeInfo.valueField] = config.options[opt];
	return c;
};

config.macros.option.genericOnChange = function(e)
{
	var opt = this.getAttribute("option");
	if(opt) {
		var optType = opt.substr(0,3);
		var handler = config.macros.option.types[optType];
		if(handler.elementType && handler.valueField)
			config.macros.option.propagateOption(opt,handler.valueField,this[handler.valueField],handler.elementType,this);
	}
	return true;
};

config.macros.option.types = {
	'txt': {
		elementType: "input",
		valueField: "value",
		eventName: "onchange",
		className: "txtOptionInput",
		create: config.macros.option.genericCreate,
		onChange: config.macros.option.genericOnChange
	},
	'chk': {
		elementType: "input",
		valueField: "checked",
		eventName: "onclick",
		className: "chkOptionInput",
		typeValue: "checkbox",
		create: config.macros.option.genericCreate,
		onChange: config.macros.option.genericOnChange
	}
};

config.macros.option.propagateOption = function(opt,valueField,value,elementType,elem)
{
	config.options[opt] = value;
	saveOptionCookie(opt);
	var nodes = document.getElementsByTagName(elementType);
	for(var t=0; t<nodes.length; t++) {
		var optNode = nodes[t].getAttribute("option");
		if(opt == optNode && nodes[t]!=elem)
			nodes[t][valueField] = value;
	}
};

config.macros.option.handler = function(place,macroName,params,wikifier,paramString)
{
	params = paramString.parseParams("anon",null,true,false,false);
	var opt = (params[1] && params[1].name == "anon") ? params[1].value : getParam(params,"name",null);
	var className = (params[2] && params[2].name == "anon") ? params[2].value : getParam(params,"class",null);
	var desc = getParam(params,"desc","no");
	var type = opt.substr(0,3);
	var h = config.macros.option.types[type];
	if(h && h.create)
		h.create(place,type,opt,className,desc);
};

config.macros.options.handler = function(place,macroName,params,wikifier,paramString)
{
	params = paramString.parseParams("anon",null,true,false,false);
	var showUnknown = getParam(params,"showUnknown","no");
	var wizard = new Wizard();
	wizard.createWizard(place,this.wizardTitle);
	wizard.addStep(this.step1Title,this.step1Html);
	var markList = wizard.getElement("markList");
	var chkUnknown = wizard.getElement("chkUnknown");
	chkUnknown.checked = showUnknown == "yes";
	chkUnknown.onchange = this.onChangeUnknown;
	var listWrapper = document.createElement("div");
	markList.parentNode.insertBefore(listWrapper,markList);
	wizard.setValue("listWrapper",listWrapper);
	this.refreshOptions(listWrapper,showUnknown == "yes");
};

config.macros.options.refreshOptions = function(listWrapper,showUnknown)
{
	var opts = [];
	for(var n in config.options) {
		var opt = {};
		opt.option = "";
		opt.name = n;
		opt.lowlight = !config.optionsDesc[n];
		opt.description = opt.lowlight ? this.unknownDescription : config.optionsDesc[n];
		if(!opt.lowlight || showUnknown)
			opts.push(opt);
	}
	opts.sort(function(a,b) {return a.name.substr(3) < b.name.substr(3) ? -1 : (a.name.substr(3) == b.name.substr(3) ? 0 : +1);});
	var listview = ListView.create(listWrapper,opts,this.listViewTemplate);
	for(n=0; n<opts.length; n++) {
		var type = opts[n].name.substr(0,3);
		var h = config.macros.option.types[type];
		if(h && h.create) {
			h.create(opts[n].colElements['option'],type,opts[n].name,null,"no");
		}
	}
};

config.macros.options.onChangeUnknown = function(e)
{
	var wizard = new Wizard(this);
	var listWrapper = wizard.getValue("listWrapper");
	removeChildren(listWrapper);
	config.macros.options.refreshOptions(listWrapper,this.checked);
	return false;
};

//--
//-- Saving
//--

var saveUsingSafari = false;

var startSaveArea = '<div id="' + 'storeArea">'; // Split up into two so that indexOf() of this source doesn't find it
var endSaveArea = '</d' + 'iv>';

// If there are unsaved changes, force the user to confirm before exitting
function confirmExit()
{
	hadConfirmExit = true;
	if((store && store.isDirty && store.isDirty()) || (story && story.areAnyDirty && story.areAnyDirty()))
		return config.messages.confirmExit;
}

// Give the user a chance to save changes before exitting
function checkUnsavedChanges()
{
	if(store && store.isDirty && store.isDirty() && window.hadConfirmExit === false) {
		if(confirm(config.messages.unsavedChangesWarning))
			saveChanges();
	}
}

function updateLanguageAttribute(s)
{
	if(config.locale) {
		var mRE = /(<html(?:.*?)?)(?: xml:lang\="([a-z]+)")?(?: lang\="([a-z]+)")?>/;
		var m = mRE.exec(s);
		if(m) {
			var t = m[1];
			if(m[2])
				t += ' xml:lang="' + config.locale + '"';
			if(m[3])
				t += ' lang="' + config.locale + '"';
			t += ">";
			s = s.substr(0,m.index) + t + s.substr(m.index+m[0].length);
		}
	}
	return s;
}

function updateMarkupBlock(s,blockName,tiddlerName)
{
	return s.replaceChunk(
			"<!--%0-START-->".format([blockName]),
			"<!--%0-END-->".format([blockName]),
			"\n" + convertUnicodeToFileFormat(store.getRecursiveTiddlerText(tiddlerName,"")) + "\n");
}

function updateOriginal(original,posDiv,localPath)
{
	if(!posDiv)
		posDiv = locateStoreArea(original);
	if(!posDiv) {
		alert(config.messages.invalidFileError.format([localPath]));
		return null;
	}
	var revised = original.substr(0,posDiv[0] + startSaveArea.length) + "\n" +
				convertUnicodeToFileFormat(store.allTiddlersAsHtml()) + "\n" +
				original.substr(posDiv[1]);
	var newSiteTitle = convertUnicodeToFileFormat(getPageTitle()).htmlEncode();
	revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
	revised = updateLanguageAttribute(revised);
	revised = updateMarkupBlock(revised,"PRE-HEAD","MarkupPreHead");
	revised = updateMarkupBlock(revised,"POST-HEAD","MarkupPostHead");
	revised = updateMarkupBlock(revised,"PRE-BODY","MarkupPreBody");
	revised = updateMarkupBlock(revised,"POST-SCRIPT","MarkupPostBody");
	return revised;
}

function locateStoreArea(original)
{
	// Locate the storeArea div's
	var posOpeningDiv = original.indexOf(startSaveArea);
	var limitClosingDiv = original.indexOf("<"+"!--POST-STOREAREA--"+">");
	if(limitClosingDiv == -1)
		limitClosingDiv = original.indexOf("<"+"!--POST-BODY-START--"+">");
	var posClosingDiv = original.lastIndexOf(endSaveArea,limitClosingDiv == -1 ? original.length : limitClosingDiv);
	return (posOpeningDiv != -1 && posClosingDiv != -1) ? [posOpeningDiv,posClosingDiv] : null;
}

function autoSaveChanges(onlyIfDirty,tiddlers)
{
	if(config.options.chkAutoSave)
		saveChanges(onlyIfDirty,tiddlers);
}

function loadOriginal(localPath)
{
	return loadFile(localPath);
}

// Save this tiddlywiki with the pending changes
function saveChanges(onlyIfDirty,tiddlers)
{
	if(onlyIfDirty && !store.isDirty())
		return;
	clearMessage();
	var t0 = new Date();
	var originalPath = document.location.toString();
	if(originalPath.substr(0,5) != "file:") {
		alert(config.messages.notFileUrlError);
		if(store.tiddlerExists(config.messages.saveInstructions))
			story.displayTiddler(null,config.messages.saveInstructions);
		return;
	}
	var localPath = getLocalPath(originalPath);
	var original = loadOriginal(localPath);
	if(original == null) {
		alert(config.messages.cantSaveError);
		if(store.tiddlerExists(config.messages.saveInstructions))
			story.displayTiddler(null,config.messages.saveInstructions);
		return;
	}
	var posDiv = locateStoreArea(original);
	if(!posDiv) {
		alert(config.messages.invalidFileError.format([localPath]));
		return;
	}
	saveMain(localPath,original,posDiv);
	if(config.options.chkSaveBackups)
		saveBackup(localPath,original);
	if(config.options.chkSaveEmptyTemplate)
		saveEmpty(localPath,original,posDiv);
	if(config.options.chkGenerateAnRssFeed && saveRss instanceof Function)
		saveRss(localPath);
	if(config.options.chkDisplayInstrumentation)
		displayMessage("saveChanges " + (new Date()-t0) + " ms");
}

function saveMain(localPath,original,posDiv)
{
	var save;
	try {
		var revised = updateOriginal(original,posDiv,localPath);
		save = saveFile(localPath,revised);
	} catch (ex) {
		showException(ex);
	}
	if(save) {
		displayMessage(config.messages.mainSaved,"file://" + localPath);
		store.setDirty(false);
	} else {
		alert(config.messages.mainFailed);
	}
}

function saveBackup(localPath,original)
{
	var backupPath = getBackupPath(localPath);
	var backup = copyFile(backupPath,localPath);
	if(!backup)
		backup = saveFile(backupPath,original);
	if(backup)
		displayMessage(config.messages.backupSaved,"file://" + backupPath);
	else
		alert(config.messages.backupFailed);
}

function saveEmpty(localPath,original,posDiv)
{
	var emptyPath,p;
	if((p = localPath.lastIndexOf("/")) != -1)
		emptyPath = localPath.substr(0,p) + "/";
	else if((p = localPath.lastIndexOf("\\")) != -1)
		emptyPath = localPath.substr(0,p) + "\\";
	else
		emptyPath = localPath + ".";
	emptyPath += "empty.html";
	var empty = original.substr(0,posDiv[0] + startSaveArea.length) + original.substr(posDiv[1]);
	var emptySave = saveFile(emptyPath,empty);
	if(emptySave)
		displayMessage(config.messages.emptySaved,"file://" + emptyPath);
	else
		alert(config.messages.emptyFailed);
}

function getLocalPath(origPath)
{
	var originalPath = convertUriToUTF8(origPath,config.options.txtFileSystemCharSet);
	// Remove any location or query part of the URL
	var argPos = originalPath.indexOf("?");
	if(argPos != -1)
		originalPath = originalPath.substr(0,argPos);
	var hashPos = originalPath.indexOf("#");
	if(hashPos != -1)
		originalPath = originalPath.substr(0,hashPos);
	// Convert file://localhost/ to file:///
	if(originalPath.indexOf("file://localhost/") == 0)
		originalPath = "file://" + originalPath.substr(16);
	// Convert to a native file format
	var localPath;
	if(originalPath.charAt(9) == ":") // pc local file
		localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\\");
	else if(originalPath.indexOf("file://///") == 0) // FireFox pc network file
		localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\\");
	else if(originalPath.indexOf("file:///") == 0) // mac/unix local file
		localPath = unescape(originalPath.substr(7));
	else if(originalPath.indexOf("file:/") == 0) // mac/unix local file
		localPath = unescape(originalPath.substr(5));
	else // pc network file
		localPath = "\\\\" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\\");
	return localPath;
}

function getBackupPath(localPath,title,extension)
{
	var slash = "\\";
	var dirPathPos = localPath.lastIndexOf("\\");
	if(dirPathPos == -1) {
		dirPathPos = localPath.lastIndexOf("/");
		slash = "/";
	}
	var backupFolder = config.options.txtBackupFolder;
	if(!backupFolder || backupFolder == "")
		backupFolder = ".";
	var backupPath = localPath.substr(0,dirPathPos) + slash + backupFolder + localPath.substr(dirPathPos);
	backupPath = backupPath.substr(0,backupPath.lastIndexOf(".")) + ".";
	if(title)
		backupPath += title.replace(/[\\\/\*\?\":<> ]/g,"_") + ".";
	backupPath += (new Date()).convertToYYYYMMDDHHMMSSMMM() + "." + (extension || "html");
	return backupPath;
}

//--
//-- RSS Saving
//--

function saveRss(localPath)
{
	var rssPath = localPath.substr(0,localPath.lastIndexOf(".")) + ".xml";
	if(saveFile(rssPath,convertUnicodeToFileFormat(generateRss())))
		displayMessage(config.messages.rssSaved,"file://" + rssPath);
	else
		alert(config.messages.rssFailed);
}

tiddlerToRssItem = function(tiddler,uri)
{
	var s = "<title" + ">" + tiddler.title.htmlEncode() + "</title" + ">\n";
	s += "<description>" + wikifyStatic(tiddler.text,null,tiddler).htmlEncode() + "</description>\n";
	for(var i=0; i<tiddler.tags.length; i++)
		s += "<category>" + tiddler.tags[i] + "</category>\n";
	s += "<link>" + uri + "#" + encodeURIComponent(String.encodeTiddlyLink(tiddler.title)) + "</link>\n";
	s +="<pubDate>" + tiddler.modified.toGMTString() + "</pubDate>\n";
	return s;
};

function generateRss()
{
	var s = [];
	var d = new Date();
	var u = store.getTiddlerText("SiteUrl");
	// Assemble the header
	s.push("<" + "?xml version=\"1.0\"?" + ">");
	s.push("<rss version=\"2.0\">");
	s.push("<channel>");
	s.push("<title" + ">" + wikifyPlain("SiteTitle").htmlEncode() + "</title" + ">");
	if(u)
		s.push("<link>" + u.htmlEncode() + "</link>");
	s.push("<description>" + wikifyPlain("SiteSubtitle").htmlEncode() + "</description>");
	s.push("<language>" + config.locale + "</language>");
	s.push("<copyright>Copyright " + d.getFullYear() + " " + config.options.txtUserName.htmlEncode() + "</copyright>");
	s.push("<pubDate>" + d.toGMTString() + "</pubDate>");
	s.push("<lastBuildDate>" + d.toGMTString() + "</lastBuildDate>");
	s.push("<docs>http://blogs.law.harvard.edu/tech/rss</docs>");
	s.push("<generator>TiddlyWiki " + formatVersion() + "</generator>");
	// The body
	var tiddlers = store.getTiddlers("modified","excludeLists");
	var n = config.numRssItems > tiddlers.length ? 0 : tiddlers.length-config.numRssItems;
	for(var i=tiddlers.length-1; i>=n; i--) {
		s.push("<item>\n" + tiddlerToRssItem(tiddlers[i],u) + "\n</item>");
	}
	// And footer
	s.push("</channel>");
	s.push("</rss>");
	// Save it all
	return s.join("\n");
}

//--
//-- Filesystem code
//--

function convertUTF8ToUnicode(u)
{
	return config.browser.isOpera || !window.netscape ? manualConvertUTF8ToUnicode(u) : mozConvertUTF8ToUnicode(u);
}

function manualConvertUTF8ToUnicode(utf)
{
	var uni = utf;
	var src = 0;
	var dst = 0;
	var b1, b2, b3;
	var c;
	while(src < utf.length) {
		b1 = utf.charCodeAt(src++);
		if(b1 < 0x80) {
			dst++;
		} else if(b1 < 0xE0) {
			b2 = utf.charCodeAt(src++);
			c = String.fromCharCode(((b1 & 0x1F) << 6) | (b2 & 0x3F));
			uni = uni.substring(0,dst++).concat(c,utf.substr(src));
		} else {
			b2 = utf.charCodeAt(src++);
			b3 = utf.charCodeAt(src++);
			c = String.fromCharCode(((b1 & 0xF) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F));
			uni = uni.substring(0,dst++).concat(c,utf.substr(src));
		}
	}
	return uni;
}

function mozConvertUTF8ToUnicode(u)
{
	try {
		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
		var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
		converter.charset = "UTF-8";
	} catch(ex) {
		return manualConvertUTF8ToUnicode(u);
	} // fallback
	var s = converter.ConvertToUnicode(u);
	var fin = converter.Finish();
	return fin.length > 0 ? s+fin : s;
}

function convertUnicodeToFileFormat(s)
{
	return config.browser.isOpera || !window.netscape ? convertUnicodeToHtmlEntities(s) : mozConvertUnicodeToUTF8(s);
}

function convertUnicodeToHtmlEntities(s)
{
	var re = /[^\u0000-\u007F]/g;
	return s.replace(re,function($0) {return "&#" + $0.charCodeAt(0).toString() + ";";});
}

function convertUnicodeToUTF8(s)
{
// return convertUnicodeToFileFormat to allow plugin migration
	return convertUnicodeToFileFormat(s);
}

function manualConvertUnicodeToUTF8(s)
{
	return unescape(encodeURIComponent(s));
}

function mozConvertUnicodeToUTF8(s)
{
	try {
		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
		var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
		converter.charset = "UTF-8";
	} catch(ex) {
		return manualConvertUnicodeToUTF8(s);
	} // fallback
	var u = converter.ConvertFromUnicode(s);
	var fin = converter.Finish();
	return fin.length > 0 ? u + fin : u;
}

function convertUriToUTF8(uri,charSet)
{
	if(window.netscape == undefined || charSet == undefined || charSet == "")
		return uri;
	try {
		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
		var converter = Components.classes["@mozilla.org/intl/utf8converterservice;1"].getService(Components.interfaces.nsIUTF8ConverterService);
	} catch(ex) {
		return uri;
	}
	return converter.convertURISpecToUTF8(uri,charSet);
}

function copyFile(dest,source)
{
	return config.browser.isIE ? ieCopyFile(dest,source) : false;
}

function saveFile(fileUrl,content)
{
	var r = mozillaSaveFile(fileUrl,content);
	if(!r)
		r = ieSaveFile(fileUrl,content);
	if(!r)
		r = javaSaveFile(fileUrl,content);
	return r;
}

function loadFile(fileUrl)
{
	var r = mozillaLoadFile(fileUrl);
	if((r == null) || (r == false))
		r = ieLoadFile(fileUrl);
	if((r == null) || (r == false))
		r = javaLoadFile(fileUrl);
	return r;
}

function ieCreatePath(path)
{
	try {
		var fso = new ActiveXObject("Scripting.FileSystemObject");
	} catch(ex) {
		return null;
	}

	var pos = path.lastIndexOf("\\");
	if(pos==-1)
		pos = path.lastIndexOf("/");
	if(pos!=-1)
		path = path.substring(0,pos+1);

	var scan = [path];
	var parent = fso.GetParentFolderName(path);
	while(parent && !fso.FolderExists(parent)) {
		scan.push(parent);
		parent = fso.GetParentFolderName(parent);
	}

	for(i=scan.length-1;i>=0;i--) {
		if(!fso.FolderExists(scan[i])) {
			fso.CreateFolder(scan[i]);
		}
	}
	return true;
}

// Returns null if it can't do it, false if there's an error, true if it saved OK
function ieSaveFile(filePath,content)
{
	ieCreatePath(filePath);
	try {
		var fso = new ActiveXObject("Scripting.FileSystemObject");
	} catch(ex) {
		return null;
	}
	var file = fso.OpenTextFile(filePath,2,-1,0);
	file.Write(content);
	file.Close();
	return true;
}

// Returns null if it can't do it, false if there's an error, or a string of the content if successful
function ieLoadFile(filePath)
{
	try {
		var fso = new ActiveXObject("Scripting.FileSystemObject");
		var file = fso.OpenTextFile(filePath,1);
		var content = file.ReadAll();
		file.Close();
	} catch(ex) {
		return null;
	}
	return content;
}

function ieCopyFile(dest,source)
{
	ieCreatePath(dest);
	try {
		var fso = new ActiveXObject("Scripting.FileSystemObject");
		fso.GetFile(source).Copy(dest);
	} catch(ex) {
		return false;
	}
	return true;
}

// Returns null if it can't do it, false if there's an error, true if it saved OK
function mozillaSaveFile(filePath,content)
{
	if(window.Components) {
		try {
			netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
			var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
			file.initWithPath(filePath);
			if(!file.exists())
				file.create(0,0664);
			var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
			out.init(file,0x20|0x02,00004,null);
			out.write(content,content.length);
			out.flush();
			out.close();
			return true;
		} catch(ex) {
			return false;
		}
	}
	return null;
}

// Returns null if it can't do it, false if there's an error, or a string of the content if successful
function mozillaLoadFile(filePath)
{
	if(window.Components) {
		try {
			netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
			var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
			file.initWithPath(filePath);
			if(!file.exists())
				return null;
			var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
			inputStream.init(file,0x01,00004,null);
			var sInputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
			sInputStream.init(inputStream);
			var contents = sInputStream.read(sInputStream.available());
			sInputStream.close();
			inputStream.close();
			return contents;
		} catch(ex) {
			return false;
		}
	}
	return null;
}

function javaUrlToFilename(url)
{
	var f = "//localhost";
	if(url.indexOf(f) == 0)
		return url.substring(f.length);
	var i = url.indexOf(":");
	return i > 0 ? url.substring(i-1) : url;
}

function javaSaveFile(filePath,content)
{
	try {
		if(document.applets["TiddlySaver"])
			return document.applets["TiddlySaver"].saveFile(javaUrlToFilename(filePath),"UTF-8",content);
	} catch(ex) {
	}
	try {
		var s = new java.io.PrintStream(new java.io.FileOutputStream(javaUrlToFilename(filePath)));
		s.print(content);
		s.close();
	} catch(ex) {
		return null;
	}
	return true;
}

function javaLoadFile(filePath)
{
	try {
		if(document.applets["TiddlySaver"])
			return String(document.applets["TiddlySaver"].loadFile(javaUrlToFilename(filePath),"UTF-8"));
	} catch(ex) {
	}
	var content = [];
	try {
		var r = new java.io.BufferedReader(new java.io.FileReader(javaUrlToFilename(filePath)));
		var line;
		while((line = r.readLine()) != null)
			content.push(new String(line));
		r.close();
	} catch(ex) {
		return null;
	}
	return content.join("\n");
}

//--
//-- Server adaptor base class
//--

function AdaptorBase()
{
	this.host = null;
	this.store = null;
	return this;
}

AdaptorBase.prototype.close = function()
{
	return true;
};

AdaptorBase.prototype.fullHostName = function(host)
{
	if(!host)
		return '';
	host = host.trim();
	if(!host.match(/:\/\//))
		host = 'http://' + host;
	if(host.substr(host.length-1) == '/')
		host = host.substr(0,host.length-1);
	return host;
};

AdaptorBase.minHostName = function(host)
{
	return host ? host.replace(/^http:\/\//,'').replace(/\/$/,'') : '';
};

AdaptorBase.prototype.setContext = function(context,userParams,callback)
{
	if(!context) context = {};
	context.userParams = userParams;
	if(callback) context.callback = callback;
	context.adaptor = this;
	if(!context.host)
		context.host = this.host;
	context.host = this.fullHostName(context.host);
	if(!context.workspace)
		context.workspace = this.workspace;
	return context;
};

// Open the specified host
AdaptorBase.prototype.openHost = function(host,context,userParams,callback)
{
	this.host = host;
	context = this.setContext(context,userParams,callback);
	context.status = true;
	if(callback)
		window.setTimeout(function() {context.callback(context,userParams);},10);
	return true;
};

// Open the specified workspace
AdaptorBase.prototype.openWorkspace = function(workspace,context,userParams,callback)
{
	this.workspace = workspace;
	context = this.setContext(context,userParams,callback);
	context.status = true;
	if(callback)
		window.setTimeout(function() {callback(context,userParams);},10);
	return true;
};

//--
//-- Server adaptor for talking to static TiddlyWiki files
//--

function FileAdaptor()
{
}

FileAdaptor.prototype = new AdaptorBase();

FileAdaptor.serverType = 'file';
FileAdaptor.serverLabel = 'TiddlyWiki';

FileAdaptor.loadTiddlyWikiCallback = function(status,context,responseText,url,xhr)
{
	context.status = status;
	if(!status) {
		context.statusText = "Error reading file";
	} else {
		context.adaptor.store = new TiddlyWiki();
		if(!context.adaptor.store.importTiddlyWiki(responseText)) {
			context.statusText = config.messages.invalidFileError.format([url]);
			context.status = false;
		}
	}
	context.complete(context,context.userParams);
};

// Get the list of workspaces on a given server
FileAdaptor.prototype.getWorkspaceList = function(context,userParams,callback)
{
	context = this.setContext(context,userParams,callback);
	context.workspaces = [{title:"(default)"}];
	context.status = true;
	if(callback)
		window.setTimeout(function() {callback(context,userParams);},10);
	return true;
};

// Gets the list of tiddlers within a given workspace
FileAdaptor.prototype.getTiddlerList = function(context,userParams,callback,filter)
{
	context = this.setContext(context,userParams,callback);
	if(!context.filter)
		context.filter = filter;
	context.complete = FileAdaptor.getTiddlerListComplete;
	if(this.store) {
		var ret = context.complete(context,context.userParams);
	} else {
		ret = loadRemoteFile(context.host,FileAdaptor.loadTiddlyWikiCallback,context);
		if(typeof ret != "string")
			ret = true;
	}
	return ret;
};

FileAdaptor.getTiddlerListComplete = function(context,userParams)
{
	if(context.status) {
		if(context.filter) {
			context.tiddlers = context.adaptor.store.filterTiddlers(context.filter);
		} else {
			context.tiddlers = [];
			context.adaptor.store.forEachTiddler(function(title,tiddler) {context.tiddlers.push(tiddler);});
		}
		for(var i=0; i<context.tiddlers.length; i++) {
			context.tiddlers[i].fields['server.type'] = FileAdaptor.serverType;
			context.tiddlers[i].fields['server.host'] = AdaptorBase.minHostName(context.host);
			context.tiddlers[i].fields['server.page.revision'] = context.tiddlers[i].modified.convertToYYYYMMDDHHMM();
		}
		context.status = true;
	}
	if(context.callback) {
		window.setTimeout(function() {context.callback(context,userParams);},10);
	}
	return true;
};

FileAdaptor.prototype.generateTiddlerInfo = function(tiddler)
{
	var info = {};
	info.uri = tiddler.fields['server.host'] + "#" + tiddler.title;
	return info;
};

// Retrieve a tiddler from a given workspace on a given server
FileAdaptor.prototype.getTiddler = function(title,context,userParams,callback)
{
	context = this.setContext(context,userParams,callback);
	context.title = title;
	context.complete = FileAdaptor.getTiddlerComplete;
	return context.adaptor.store ?
		context.complete(context,context.userParams) :
		loadRemoteFile(context.host,FileAdaptor.loadTiddlyWikiCallback,context);
};

FileAdaptor.getTiddlerComplete = function(context,userParams)
{
	var t = context.adaptor.store.fetchTiddler(context.title);
	if(t) {
		t.fields['server.type'] = FileAdaptor.serverType;
		t.fields['server.host'] = AdaptorBase.minHostName(context.host);
		t.fields['server.page.revision'] = t.modified.convertToYYYYMMDDHHMM();
		context.tiddler = t;
		context.status = true;
	} else { //# tiddler does not exist in document
		context.status = false;
	}
	if(context.allowSynchronous) {
		context.isSynchronous = true;
		context.callback(context,userParams);
	} else {
		window.setTimeout(function() {context.callback(context,userParams);},10);
	}
	return true;
};

FileAdaptor.prototype.close = function()
{
	delete this.store;
	this.store = null;
};

config.adaptors[FileAdaptor.serverType] = FileAdaptor;

config.defaultAdaptor = FileAdaptor.serverType;

//--
//-- HTTP request code
//--

function ajaxReq(args)
{
	if(window.Components && window.netscape && window.netscape.security && document.location.protocol.indexOf("http") == -1)
		window.netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
	return jQuery.ajax(args);
}

//--
//-- TiddlyWiki-specific utility functions
//--

// Returns TiddlyWiki version string
function formatVersion(v)
{
	v = v || version;
	return v.major + "." + v.minor + "." + v.revision +
		(v.alpha ? " (alpha " + v.alpha + ")" : "") +
		(v.beta ? " (beta " + v.beta + ")" : "");
}

function compareVersions(v1,v2)
{
	var a = ["major","minor","revision"];
	for(var i = 0; i<a.length; i++) {
		var x1 = v1[a[i]] || 0;
		var x2 = v2[a[i]] || 0;
		if(x1<x2)
			return 1;
		if(x1>x2)
			return -1;
	}
	x1 = v1.beta || 9999;
	x2 = v2.beta || 9999;
	if(x1<x2)
		return 1;
	return x1 > x2 ? -1 : 0;
}

function createTiddlyButton(parent,text,tooltip,action,className,id,accessKey,attribs)
{
	var btn = document.createElement("a");
	if(action) {
		btn.onclick = action;
		btn.setAttribute("href","javascript:;");
	}
	if(tooltip)
		btn.setAttribute("title",tooltip);
	if(text)
		btn.appendChild(document.createTextNode(text));
	btn.className = className || "button";
	if(id)
		btn.id = id;
	if(attribs) {
		for(var i in attribs) {
			btn.setAttribute(i,attribs[i]);
		}
	}
	if(parent)
		parent.appendChild(btn);
	if(accessKey)
		btn.setAttribute("accessKey",accessKey);
	return btn;
}

function createTiddlyLink(place,title,includeText,className,isStatic,linkedFromTiddler,noToggle)
{
	var text = includeText ? title : null;
	var i = getTiddlyLinkInfo(title,className);
	var btn = isStatic ? createExternalLink(place,store.getTiddlerText("SiteUrl",null) + "#" + title) : createTiddlyButton(place,text,i.subTitle,onClickTiddlerLink,i.classes);
	if(isStatic)
		btn.className += ' ' + className;
	btn.setAttribute("refresh","link");
	btn.setAttribute("tiddlyLink",title);
	if(noToggle)
		btn.setAttribute("noToggle","true");
	if(linkedFromTiddler) {
		var fields = linkedFromTiddler.getInheritedFields();
		if(fields)
			btn.setAttribute("tiddlyFields",fields);
	}
	return btn;
}

function refreshTiddlyLink(e,title)
{
	var i = getTiddlyLinkInfo(title,e.className);
	e.className = i.classes;
	e.title = i.subTitle;
}

function getTiddlyLinkInfo(title,currClasses)
{
	var classes = currClasses ? currClasses.split(" ") : [];
	classes.pushUnique("tiddlyLink");
	var tiddler = store.fetchTiddler(title);
	var subTitle;
	if(tiddler) {
		subTitle = tiddler.getSubtitle();
		classes.pushUnique("tiddlyLinkExisting");
		classes.remove("tiddlyLinkNonExisting");
		classes.remove("shadow");
	} else {
		classes.remove("tiddlyLinkExisting");
		classes.pushUnique("tiddlyLinkNonExisting");
		if(store.isShadowTiddler(title)) {
			subTitle = config.messages.shadowedTiddlerToolTip.format([title]);
			classes.pushUnique("shadow");
		} else {
			subTitle = config.messages.undefinedTiddlerToolTip.format([title]);
			classes.remove("shadow");
		}
	}
	if(typeof config.annotations[title]=="string")
		subTitle = config.annotations[title];
	return {classes: classes.join(" "),subTitle: subTitle};
}

function createExternalLink(place,url,label)
{
	var link = document.createElement("a");
	link.className = "externalLink";
	link.href = url;
	link.title = config.messages.externalLinkTooltip.format([url]);
	if(config.options.chkOpenInNewWindow)
		link.target = "_blank";
	place.appendChild(link);
	if(label)
		createTiddlyText(link, label);
	return link;
}

// Event handler for clicking on a tiddly link
function onClickTiddlerLink(ev)
{
	var e = ev || window.event;
	var target = resolveTarget(e);
	var link = target;
	var title = null;
	var fields = null;
	var noToggle = null;
	do {
		title = link.getAttribute("tiddlyLink");
		fields = link.getAttribute("tiddlyFields");
		noToggle = link.getAttribute("noToggle");
		link = link.parentNode;
	} while(title == null && link != null);
	if(!store.isShadowTiddler(title)) {
		var f = fields ? fields.decodeHashMap() : {};
		fields = String.encodeHashMap(merge(f,config.defaultCustomFields,true));
	}
	if(title) {
		var toggling = e.metaKey || e.ctrlKey;
		if(config.options.chkToggleLinks)
			toggling = !toggling;
		if(noToggle)
			toggling = false;
		if(store.getTiddler(title))
			fields = null;
		story.displayTiddler(target,title,null,true,null,fields,toggling);
	}
	clearMessage();
	return false;
}

// Create a button for a tag with a popup listing all the tiddlers that it tags
function createTagButton(place,tag,excludeTiddler,title,tooltip)
{
	var btn = createTiddlyButton(place,title||tag,(tooltip||config.views.wikified.tag.tooltip).format([tag]),onClickTag);
	btn.setAttribute("tag",tag);
	if(excludeTiddler)
		btn.setAttribute("tiddler",excludeTiddler);
	return btn;
}

// Event handler for clicking on a tiddler tag
function onClickTag(ev)
{
	var e = ev || window.event;
	var popup = Popup.create(this);
	addClass(popup,"taggedTiddlerList");
	var tag = this.getAttribute("tag");
	var title = this.getAttribute("tiddler");
	if(popup && tag) {
		var tagged = store.getTaggedTiddlers(tag);
		var titles = [];
		var li,r;
		for(r=0;r<tagged.length;r++) {
			if(tagged[r].title != title)
				titles.push(tagged[r].title);
		}
		var lingo = config.views.wikified.tag;
		if(titles.length > 0) {
			var openAll = createTiddlyButton(createTiddlyElement(popup,"li"),lingo.openAllText.format([tag]),lingo.openAllTooltip,onClickTagOpenAll);
			openAll.setAttribute("tag",tag);
			createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
			for(r=0; r<titles.length; r++) {
				createTiddlyLink(createTiddlyElement(popup,"li"),titles[r],true);
			}
		} else {
			createTiddlyElement(popup,"li",null,"disabled",lingo.popupNone.format([tag]));
		}
		createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
		var h = createTiddlyLink(createTiddlyElement(popup,"li"),tag,false);
		createTiddlyText(h,lingo.openTag.format([tag]));
	}
	Popup.show();
	e.cancelBubble = true;
	if(e.stopPropagation) e.stopPropagation();
	return false;
}

// Event handler for 'open all' on a tiddler popup
function onClickTagOpenAll(ev)
{
	var tiddlers = store.getTaggedTiddlers(this.getAttribute("tag"));
	story.displayTiddlers(this,tiddlers);
	return false;
}

function onClickError(ev)
{
	var e = ev || window.event;
	var popup = Popup.create(this);
	var lines = this.getAttribute("errorText").split("\n");
	for(var t=0; t<lines.length; t++)
		createTiddlyElement(popup,"li",null,null,lines[t]);
	Popup.show();
	e.cancelBubble = true;
	if(e.stopPropagation) e.stopPropagation();
	return false;
}

function createTiddlyDropDown(place,onchange,options,defaultValue)
{
	var sel = createTiddlyElement(place,"select");
	sel.onchange = onchange;
	for(var t=0; t<options.length; t++) {
		var e = createTiddlyElement(sel,"option",null,null,options[t].caption);
		e.value = options[t].name;
		if(options[t].name == defaultValue)
			e.selected = true;
	}
	return sel;
}

function createTiddlyPopup(place,caption,tooltip,tiddler)
{
	if(tiddler.text) {
		createTiddlyLink(place,caption,true);
		var btn = createTiddlyButton(place,glyph("downArrow"),tooltip,onClickTiddlyPopup,"tiddlerPopupButton");
		btn.tiddler = tiddler;
	} else {
		createTiddlyText(place,caption);
	}
}

function onClickTiddlyPopup(ev)
{
	var e = ev || window.event;
	var tiddler = this.tiddler;
	if(tiddler.text) {
		var popup = Popup.create(this,"div","popupTiddler");
		wikify(tiddler.text,popup,null,tiddler);
		Popup.show();
	}
	if(e) e.cancelBubble = true;
	if(e && e.stopPropagation) e.stopPropagation();
	return false;
}

function createTiddlyError(place,title,text)
{
	var btn = createTiddlyButton(place,title,null,onClickError,"errorButton");
	if(text) btn.setAttribute("errorText",text);
}

function merge(dst,src,preserveExisting)
{
	for(var i in src) {
		if(!preserveExisting || dst[i] === undefined)
			dst[i] = src[i];
	}
	return dst;
}

// Returns a string containing the description of an exception, optionally prepended by a message
function exceptionText(e,message)
{
	var s = e.description || e.toString();
	return message ? "%0:\n%1".format([message,s]) : s;
}

// Displays an alert of an exception description with optional message
function showException(e,message)
{
	alert(exceptionText(e,message));
}

function alertAndThrow(m)
{
	alert(m);
	throw(m);
}

function glyph(name)
{
	var g = config.glyphs;
	var b = g.currBrowser;
	if(b == null) {
		b = 0;
		while(!g.browsers[b]() && b < g.browsers.length-1)
			b++;
		g.currBrowser = b;
	}
	if(!g.codes[name])
		return "";
	return g.codes[name][b];
}

if(!window.console) {
	console = {tiddlywiki:true,log:function(message) {displayMessage(message);}};
}

//-
//- Animation engine
//-

function Animator()
{
	this.running = 0; // Incremented at start of each animation, decremented afterwards. If zero, the interval timer is disabled
	this.timerID = 0; // ID of the timer used for animating
	this.animations = []; // List of animations in progress
	return this;
}

// Start animation engine
Animator.prototype.startAnimating = function() //# Variable number of arguments
{
	for(var t=0; t<arguments.length; t++)
		this.animations.push(arguments[t]);
	if(this.running == 0) {
		var me = this;
		this.timerID = window.setInterval(function() {me.doAnimate(me);},10);
	}
	this.running += arguments.length;
};

// Perform an animation engine tick, calling each of the known animation modules
Animator.prototype.doAnimate = function(me)
{
	var a = 0;
	while(a < me.animations.length) {
		var animation = me.animations[a];
		if(animation.tick()) {
			a++;
		} else {
			me.animations.splice(a,1);
			if(--me.running == 0)
				window.clearInterval(me.timerID);
		}
	}
};

Animator.slowInSlowOut = function(progress)
{
	return(1-((Math.cos(progress * Math.PI)+1)/2));
};

//--
//-- Morpher animation
//--

// Animate a set of properties of an element
function Morpher(element,duration,properties,callback)
{
	this.element = element;
	this.duration = duration;
	this.properties = properties;
	this.startTime = new Date();
	this.endTime = Number(this.startTime) + duration;
	this.callback = callback;
	this.tick();
	return this;
}

Morpher.prototype.assignStyle = function(element,style,value)
{
	switch(style) {
	case "-tw-vertScroll":
		window.scrollTo(findScrollX(),value);
		break;
	case "-tw-horizScroll":
		window.scrollTo(value,findScrollY());
		break;
	default:
		element.style[style] = value;
		break;
	}
};

Morpher.prototype.stop = function()
{
	for(var t=0; t<this.properties.length; t++) {
		var p = this.properties[t];
		if(p.atEnd !== undefined) {
			this.assignStyle(this.element,p.style,p.atEnd);
		}
	}
	if(this.callback)
		this.callback(this.element,this.properties);
};

Morpher.prototype.tick = function()
{
	var currTime = Number(new Date());
	var progress = Animator.slowInSlowOut(Math.min(1,(currTime-this.startTime)/this.duration));
	for(var t=0; t<this.properties.length; t++) {
		var p = this.properties[t];
		if(p.start !== undefined && p.end !== undefined) {
			var template = p.template || "%0";
			switch(p.format) {
			case undefined:
			case "style":
				var v = p.start + (p.end-p.start) * progress;
				this.assignStyle(this.element,p.style,template.format([v]));
				break;
			case "color":
				break;
			}
		}
	}
	if(currTime >= this.endTime) {
		this.stop();
		return false;
	}
	return true;
};

//--
//-- Zoomer animation
//--

function Zoomer(text,startElement,targetElement,unused)
{
	var e = createTiddlyElement(document.body,"div",null,"zoomer");
	createTiddlyElement(e,"div",null,null,text);
	var winWidth = findWindowWidth();
	var winHeight = findWindowHeight();
	var p = [
		{style: 'left', start: findPosX(startElement), end: findPosX(targetElement), template: '%0px'},
		{style: 'top', start: findPosY(startElement), end: findPosY(targetElement), template: '%0px'},
		{style: 'width', start: Math.min(startElement.scrollWidth,winWidth), end: Math.min(targetElement.scrollWidth,winWidth), template: '%0px', atEnd: 'auto'},
		{style: 'height', start: Math.min(startElement.scrollHeight,winHeight), end: Math.min(targetElement.scrollHeight,winHeight), template: '%0px', atEnd: 'auto'},
		{style: 'fontSize', start: 8, end: 24, template: '%0pt'}
	];
	var c = function(element,properties) {removeNode(element);};
	return new Morpher(e,config.animDuration,p,c);
}

//--
//-- Scroller animation
//--

function Scroller(targetElement)
{
	var p = [{style: '-tw-vertScroll', start: findScrollY(), end: ensureVisible(targetElement)}];
	return new Morpher(targetElement,config.animDuration,p);
}

//--
//-- Slider animation
//--

// deleteMode - "none", "all" [delete target element and it's children], [only] "children" [but not the target element]
function Slider(element,opening,unused,deleteMode)
{
	element.style.overflow = 'hidden';
	if(opening)
		element.style.height = '0px'; // Resolves a Firefox flashing bug
	element.style.display = 'block';
	var left = findPosX(element);
	var width = element.scrollWidth;
	var height = element.scrollHeight;
	var winWidth = findWindowWidth();
	var p = [];
	var c = null;
	if(opening) {
		p.push({style: 'height', start: 0, end: height, template: '%0px', atEnd: 'auto'});
		p.push({style: 'opacity', start: 0, end: 1, template: '%0'});
		p.push({style: 'filter', start: 0, end: 100, template: 'alpha(opacity:%0)'});
	} else {
		p.push({style: 'height', start: height, end: 0, template: '%0px'});
		p.push({style: 'display', atEnd: 'none'});
		p.push({style: 'opacity', start: 1, end: 0, template: '%0'});
		p.push({style: 'filter', start: 100, end: 0, template: 'alpha(opacity:%0)'});
		switch(deleteMode) {
		case "all":
			c = function(element,properties) {removeNode(element);};
			break;
		case "children":
			c = function(element,properties) {removeChildren(element);};
			break;
		}
	}
	return new Morpher(element,config.animDuration,p,c);
}

//--
//-- Popup menu
//--

var Popup = {
	stack: [] // Array of objects with members root: and popup:
	};

Popup.create = function(root,elem,className)
{
	var stackPosition = this.find(root,"popup");
	Popup.remove(stackPosition+1);
	var popup = createTiddlyElement(document.body,elem || "ol","popup",className || "popup");
	popup.stackPosition = stackPosition;
	Popup.stack.push({root: root, popup: popup});
	return popup;
};

Popup.onDocumentClick = function(ev)
{
	var e = ev || window.event;
	if(e.eventPhase == undefined)
		Popup.remove();
	else if(e.eventPhase == Event.BUBBLING_PHASE || e.eventPhase == Event.AT_TARGET)
		Popup.remove();
	return true;
};

Popup.show = function(valign,halign,offset)
{
	var curr = Popup.stack[Popup.stack.length-1];
	this.place(curr.root,curr.popup,valign,halign,offset);
	addClass(curr.root,"highlight");
	if(config.options.chkAnimate && anim && typeof Scroller == "function")
		anim.startAnimating(new Scroller(curr.popup));
	else
		window.scrollTo(0,ensureVisible(curr.popup));
};

Popup.place = function(root,popup,valign,halign,offset)
{
	if(!offset)
		var offset = {x:0,y:0};
	if(popup.stackPosition >= 0 && !valign && !halign) {
		offset.x = offset.x + root.offsetWidth;
	} else {
		offset.x = (halign == "right") ? offset.x + root.offsetWidth : offset.x;
		offset.y = (valign == "top") ? offset.y : offset.y + root.offsetHeight;
	}
	var rootLeft = findPosX(root);
	var rootTop = findPosY(root);
	var popupLeft = rootLeft + offset.x;
	var popupTop = rootTop + offset.y;
	var winWidth = findWindowWidth();
	if(popup.offsetWidth > winWidth*0.75)
		popup.style.width = winWidth*0.75 + "px";
	var popupWidth = popup.offsetWidth;
	var scrollWidth = winWidth - document.body.offsetWidth;
	if(popupLeft + popupWidth > winWidth - scrollWidth - 1) {
		if(halign == "right")
			popupLeft = popupLeft - root.offsetWidth - popupWidth;
		else
			popupLeft = winWidth - popupWidth - scrollWidth - 1;
	}
	popup.style.left = popupLeft + "px";
	popup.style.top = popupTop + "px";
	popup.style.display = "block";
};

Popup.find = function(e)
{
	var pos = -1;
	for (var t=this.stack.length-1; t>=0; t--) {
		if(isDescendant(e,this.stack[t].popup))
			pos = t;
	}
	return pos;
};

Popup.remove = function(pos)
{
	if(!pos) var pos = 0;
	if(Popup.stack.length > pos) {
		Popup.removeFrom(pos);
	}
};

Popup.removeFrom = function(from)
{
	for(var t=Popup.stack.length-1; t>=from; t--) {
		var p = Popup.stack[t];
		removeClass(p.root,"highlight");
		removeNode(p.popup);
	}
	Popup.stack = Popup.stack.slice(0,from);
};

//--
//-- Wizard support
//--

function Wizard(elem)
{
	if(elem) {
		this.formElem = findRelated(elem,"wizard","className");
		this.bodyElem = findRelated(this.formElem.firstChild,"wizardBody","className","nextSibling");
		this.footElem = findRelated(this.formElem.firstChild,"wizardFooter","className","nextSibling");
	} else {
		this.formElem = null;
		this.bodyElem = null;
		this.footElem = null;
	}
}

Wizard.prototype.setValue = function(name,value)
{
	if(this.formElem)
		this.formElem[name] = value;
};

Wizard.prototype.getValue = function(name)
{
	return this.formElem ? this.formElem[name] : null;
};

Wizard.prototype.createWizard = function(place,title)
{
	this.formElem = createTiddlyElement(place,"form",null,"wizard");
	createTiddlyElement(this.formElem,"h1",null,null,title);
	this.bodyElem = createTiddlyElement(this.formElem,"div",null,"wizardBody");
	this.footElem = createTiddlyElement(this.formElem,"div",null,"wizardFooter");
};

Wizard.prototype.clear = function()
{
	removeChildren(this.bodyElem);
};

Wizard.prototype.setButtons = function(buttonInfo,status)
{
	removeChildren(this.footElem);
	for(var t=0; t<buttonInfo.length; t++) {
		createTiddlyButton(this.footElem,buttonInfo[t].caption,buttonInfo[t].tooltip,buttonInfo[t].onClick);
		insertSpacer(this.footElem);
		}
	if(typeof status == "string") {
		createTiddlyElement(this.footElem,"span",null,"status",status);
	}
};

Wizard.prototype.addStep = function(stepTitle,html)
{
	removeChildren(this.bodyElem);
	var w = createTiddlyElement(this.bodyElem,"div");
	createTiddlyElement(w,"h2",null,null,stepTitle);
	var step = createTiddlyElement(w,"div",null,"wizardStep");
	step.innerHTML = html;
	applyHtmlMacros(step,tiddler);
};

Wizard.prototype.getElement = function(name)
{
	return this.formElem.elements[name];
};

//--
//-- ListView gadget
//--

var ListView = {};

// Create a listview
ListView.create = function(place,listObject,listTemplate,callback,className)
{
	var table = createTiddlyElement(place,"table",null,className || "listView twtable");
	var thead = createTiddlyElement(table,"thead");
	var r = createTiddlyElement(thead,"tr");
	for(var t=0; t<listTemplate.columns.length; t++) {
		var columnTemplate = listTemplate.columns[t];
		var c = createTiddlyElement(r,"th");
		var colType = ListView.columnTypes[columnTemplate.type];
		if(colType && colType.createHeader) {
			colType.createHeader(c,columnTemplate,t);
			if(columnTemplate.className)
				addClass(c,columnTemplate.className);
		}
	}
	var tbody = createTiddlyElement(table,"tbody");
	for(var rc=0; rc<listObject.length; rc++) {
		var rowObject = listObject[rc];
		r = createTiddlyElement(tbody,"tr");
		for(c=0; c<listTemplate.rowClasses.length; c++) {
			if(rowObject[listTemplate.rowClasses[c].field])
				addClass(r,listTemplate.rowClasses[c].className);
		}
		rowObject.rowElement = r;
		rowObject.colElements = {};
		for(var cc=0; cc<listTemplate.columns.length; cc++) {
			c = createTiddlyElement(r,"td");
			columnTemplate = listTemplate.columns[cc];
			var field = columnTemplate.field;
			colType = ListView.columnTypes[columnTemplate.type];
			if(colType && colType.createItem) {
				colType.createItem(c,rowObject,field,columnTemplate,cc,rc);
				if(columnTemplate.className)
					addClass(c,columnTemplate.className);
			}
			rowObject.colElements[field] = c;
		}
	}
	if(callback && listTemplate.actions)
		createTiddlyDropDown(place,ListView.getCommandHandler(callback),listTemplate.actions);
	if(callback && listTemplate.buttons) {
		for(t=0; t<listTemplate.buttons.length; t++) {
			var a = listTemplate.buttons[t];
			if(a && a.name != "")
				createTiddlyButton(place,a.caption,null,ListView.getCommandHandler(callback,a.name,a.allowEmptySelection));
		}
	}
	return table;
};

ListView.getCommandHandler = function(callback,name,allowEmptySelection)
{
	return function(e) {
		var view = findRelated(this,"TABLE",null,"previousSibling");
		var tiddlers = [];
		ListView.forEachSelector(view,function(e,rowName) {
					if(e.checked)
						tiddlers.push(rowName);
					});
		if(tiddlers.length == 0 && !allowEmptySelection) {
			alert(config.messages.nothingSelected);
		} else {
			if(this.nodeName.toLowerCase() == "select") {
				callback(view,this.value,tiddlers);
				this.selectedIndex = 0;
			} else {
				callback(view,name,tiddlers);
			}
		}
	};
};

// Invoke a callback for each selector checkbox in the listview
ListView.forEachSelector = function(view,callback)
{
	var checkboxes = view.getElementsByTagName("input");
	var hadOne = false;
	for(var t=0; t<checkboxes.length; t++) {
		var cb = checkboxes[t];
		if(cb.getAttribute("type") == "checkbox") {
			var rn = cb.getAttribute("rowName");
			if(rn) {
				callback(cb,rn);
				hadOne = true;
			}
		}
	}
	return hadOne;
};

ListView.getSelectedRows = function(view)
{
	var rowNames = [];
	ListView.forEachSelector(view,function(e,rowName) {
				if(e.checked)
					rowNames.push(rowName);
				});
	return rowNames;
};

ListView.columnTypes = {};

ListView.columnTypes.String = {
	createHeader: function(place,columnTemplate,col)
		{
			createTiddlyText(place,columnTemplate.title);
		},
	createItem: function(place,listObject,field,columnTemplate,col,row)
		{
			var v = listObject[field];
			if(v != undefined)
				createTiddlyText(place,v);
		}
};

ListView.columnTypes.WikiText = {
	createHeader: ListView.columnTypes.String.createHeader,
	createItem: function(place,listObject,field,columnTemplate,col,row)
		{
			var v = listObject[field];
			if(v != undefined)
				wikify(v,place,null,null);
		}
};

ListView.columnTypes.Tiddler = {
	createHeader: ListView.columnTypes.String.createHeader,
	createItem: function(place,listObject,field,columnTemplate,col,row)
		{
			var v = listObject[field];
			if(v != undefined && v.title)
				createTiddlyPopup(place,v.title,config.messages.listView.tiddlerTooltip,v);
		}
};

ListView.columnTypes.Size = {
	createHeader: ListView.columnTypes.String.createHeader,
	createItem: function(place,listObject,field,columnTemplate,col,row)
		{
			var v = listObject[field];
			if(v != undefined) {
				var t = 0;
				while(t<config.messages.sizeTemplates.length-1 && v<config.messages.sizeTemplates[t].unit)
					t++;
				createTiddlyText(place,config.messages.sizeTemplates[t].template.format([Math.round(v/config.messages.sizeTemplates[t].unit)]));
			}
		}
};

ListView.columnTypes.Link = {
	createHeader: ListView.columnTypes.String.createHeader,
	createItem: function(place,listObject,field,columnTemplate,col,row)
		{
			var v = listObject[field];
			var c = columnTemplate.text;
			if(v != undefined)
				createExternalLink(place,v,c || v);
		}
};

ListView.columnTypes.Date = {
	createHeader: ListView.columnTypes.String.createHeader,
	createItem: function(place,listObject,field,columnTemplate,col,row)
		{
			var v = listObject[field];
			if(v != undefined)
				createTiddlyText(place,v.formatString(columnTemplate.dateFormat));
		}
};

ListView.columnTypes.StringList = {
	createHeader: ListView.columnTypes.String.createHeader,
	createItem: function(place,listObject,field,columnTemplate,col,row)
		{
			var v = listObject[field];
			if(v != undefined) {
				for(var t=0; t<v.length; t++) {
					createTiddlyText(place,v[t]);
					createTiddlyElement(place,"br");
				}
			}
		}
};

ListView.columnTypes.Selector = {
	createHeader: function(place,columnTemplate,col)
		{
			createTiddlyCheckbox(place,null,false,this.onHeaderChange);
		},
	createItem: function(place,listObject,field,columnTemplate,col,row)
		{
			var e = createTiddlyCheckbox(place,null,listObject[field],null);
			e.setAttribute("rowName",listObject[columnTemplate.rowName]);
		},
	onHeaderChange: function(e)
		{
			var state = this.checked;
			var view = findRelated(this,"TABLE");
			if(!view)
				return;
			ListView.forEachSelector(view,function(e,rowName) {
								e.checked = state;
							});
		}
};

ListView.columnTypes.Tags = {
	createHeader: ListView.columnTypes.String.createHeader,
	createItem: function(place,listObject,field,columnTemplate,col,row)
		{
			var tags = listObject[field];
			createTiddlyText(place,String.encodeTiddlyLinkList(tags));
		}
};

ListView.columnTypes.Boolean = {
	createHeader: ListView.columnTypes.String.createHeader,
	createItem: function(place,listObject,field,columnTemplate,col,row)
		{
			if(listObject[field] == true)
				createTiddlyText(place,columnTemplate.trueText);
			if(listObject[field] == false)
				createTiddlyText(place,columnTemplate.falseText);
		}
};

ListView.columnTypes.TagCheckbox = {
	createHeader: ListView.columnTypes.String.createHeader,
	createItem: function(place,listObject,field,columnTemplate,col,row)
		{
			var e = createTiddlyCheckbox(place,null,listObject[field],this.onChange);
			e.setAttribute("tiddler",listObject.title);
			e.setAttribute("tag",columnTemplate.tag);
		},
	onChange : function(e)
		{
			var tag = this.getAttribute("tag");
			var tiddler = this.getAttribute("tiddler");
			store.setTiddlerTag(tiddler,this.checked,tag);
		}
};

ListView.columnTypes.TiddlerLink = {
	createHeader: ListView.columnTypes.String.createHeader,
	createItem: function(place,listObject,field,columnTemplate,col,row)
		{
			var v = listObject[field];
			if(v != undefined) {
				var link = createTiddlyLink(place,listObject[columnTemplate.tiddlerLink],false,null);
				createTiddlyText(link,listObject[field]);
			}
		}
};

//--
//-- Augmented methods for the JavaScript Number(), Array(), String() and Date() objects
//--

// Clamp a number to a range
Number.prototype.clamp = function(min,max)
{
	var c = this;
	if(c < min)
		c = min;
	if(c > max)
		c = max;
	return Number(c);
};

// Add indexOf function if browser does not support it
if(!Array.indexOf) {
Array.prototype.indexOf = function(item,from)
{
	if(!from)
		from = 0;
	for(var i=from; i<this.length; i++) {
		if(this[i] === item)
			return i;
	}
	return -1;
};}

// Find an entry in a given field of the members of an array
Array.prototype.findByField = function(field,value)
{
	for(var t=0; t<this.length; t++) {
		if(this[t][field] === value)
			return t;
	}
	return null;
};

// Return whether an entry exists in an array
Array.prototype.contains = function(item)
{
	return this.indexOf(item) != -1;
};

// Adds, removes or toggles a particular value within an array
//  value - value to add
//  mode - +1 to add value, -1 to remove value, 0 to toggle it
Array.prototype.setItem = function(value,mode)
{
	var p = this.indexOf(value);
	if(mode == 0)
		mode = (p == -1) ? +1 : -1;
	if(mode == +1) {
		if(p == -1)
			this.push(value);
	} else if(mode == -1) {
		if(p != -1)
			this.splice(p,1);
	}
};

// Return whether one of a list of values exists in an array
Array.prototype.containsAny = function(items)
{
	for(var i=0; i<items.length; i++) {
		if(this.indexOf(items[i]) != -1)
			return true;
	}
	return false;
};

// Return whether all of a list of values exists in an array
Array.prototype.containsAll = function(items)
{
	for(var i = 0; i<items.length; i++) {
		if(this.indexOf(items[i]) == -1)
			return false;
	}
	return true;
};

// Push a new value into an array only if it is not already present in the array. If the optional unique parameter is false, it reverts to a normal push
Array.prototype.pushUnique = function(item,unique)
{
	if(unique === false) {
		this.push(item);
	} else {
		if(this.indexOf(item) == -1)
			this.push(item);
	}
};

Array.prototype.remove = function(item)
{
	var p = this.indexOf(item);
	if(p != -1)
		this.splice(p,1);
};

if(!Array.prototype.map) {
Array.prototype.map = function(fn,thisObj)
{
	var scope = thisObj || window;
	var a = [];
	for(var i=0, j=this.length; i < j; ++i) {
		a.push(fn.call(scope,this[i],i,this));
	}
	return a;
};}

// Get characters from the right end of a string
String.prototype.right = function(n)
{
	return n < this.length ? this.slice(this.length-n) : this;
};

// Trim whitespace from both ends of a string
String.prototype.trim = function()
{
	return this.replace(/^\s*|\s*$/g,"");
};

// Convert a string from a CSS style property name to a JavaScript style name ("background-color" -> "backgroundColor")
String.prototype.unDash = function()
{
	var s = this.split("-");
	if(s.length > 1) {
		for(var t=1; t<s.length; t++)
			s[t] = s[t].substr(0,1).toUpperCase() + s[t].substr(1);
	}
	return s.join("");
};

// Substitute substrings from an array into a format string that includes '%1'-type specifiers
String.prototype.format = function(substrings)
{
	var subRegExp = /(?:%(\d+))/mg;
	var currPos = 0;
	var r = [];
	do {
		var match = subRegExp.exec(this);
		if(match && match[1]) {
			if(match.index > currPos)
				r.push(this.substring(currPos,match.index));
			r.push(substrings[parseInt(match[1])]);
			currPos = subRegExp.lastIndex;
		}
	} while(match);
	if(currPos < this.length)
		r.push(this.substring(currPos,this.length));
	return r.join("");
};

// Escape any special RegExp characters with that character preceded by a backslash
String.prototype.escapeRegExp = function()
{
	var s = "\\^$*+?()=!|,{}[].";
	var c = this;
	for(var t=0; t<s.length; t++)
		c = c.replace(new RegExp("\\" + s.substr(t,1),"g"),"\\" + s.substr(t,1));
	return c;
};

// Convert "\" to "\s", newlines to "\n" (and remove carriage returns)
String.prototype.escapeLineBreaks = function()
{
	return this.replace(/\\/mg,"\\s").replace(/\n/mg,"\\n").replace(/\r/mg,"");
};

// Convert "\n" to newlines, "\b" to " ", "\s" to "\" (and remove carriage returns)
String.prototype.unescapeLineBreaks = function()
{
	return this.replace(/\\n/mg,"\n").replace(/\\b/mg," ").replace(/\\s/mg,"\\").replace(/\r/mg,"");
};

// Convert & to "&amp;", < to "&lt;", > to "&gt;" and " to "&quot;"
String.prototype.htmlEncode = function()
{
	return this.replace(/&/mg,"&amp;").replace(/</mg,"&lt;").replace(/>/mg,"&gt;").replace(/\"/mg,"&quot;");
};

// Convert "&amp;" to &, "&lt;" to <, "&gt;" to > and "&quot;" to "
String.prototype.htmlDecode = function()
{
	return this.replace(/&lt;/mg,"<").replace(/&gt;/mg,">").replace(/&quot;/mg,"\"").replace(/&amp;/mg,"&");
};

// Parse a space-separated string of name:value parameters
// The result is an array of objects:
//   result[0] = object with a member for each parameter name, value of that member being an array of values
//   result[1..n] = one object for each parameter, with 'name' and 'value' members
String.prototype.parseParams = function(defaultName,defaultValue,allowEval,noNames,cascadeDefaults)
{
	var parseToken = function(match,p) {
		var n;
		if(match[p]) // Double quoted
			n = match[p];
		else if(match[p+1]) // Single quoted
			n = match[p+1];
		else if(match[p+2]) // Double-square-bracket quoted
			n = match[p+2];
		else if(match[p+3]) // Double-brace quoted
			try {
				n = match[p+3];
				if(allowEval)
					n = window.eval(n);
			} catch(ex) {
				throw "Unable to evaluate {{" + match[p+3] + "}}: " + exceptionText(ex);
			}
		else if(match[p+4]) // Unquoted
			n = match[p+4];
		else if(match[p+5]) // empty quote
			n = "";
		return n;
	};
	var r = [{}];
	var dblQuote = "(?:\"((?:(?:\\\\\")|[^\"])+)\")";
	var sngQuote = "(?:'((?:(?:\\\\\')|[^'])+)')";
	var dblSquare = "(?:\\[\\[((?:\\s|\\S)*?)\\]\\])";
	var dblBrace = "(?:\\{\\{((?:\\s|\\S)*?)\\}\\})";
	var unQuoted = noNames ? "([^\"'\\s]\\S*)" : "([^\"':\\s][^\\s:]*)";
	var emptyQuote = "((?:\"\")|(?:''))";
	var skipSpace = "(?:\\s*)";
	var token = "(?:" + dblQuote + "|" + sngQuote + "|" + dblSquare + "|" + dblBrace + "|" + unQuoted + "|" + emptyQuote + ")";
	var re = noNames ? new RegExp(token,"mg") : new RegExp(skipSpace + token + skipSpace + "(?:(\\:)" + skipSpace + token + ")?","mg");
	var params = [];
	do {
		var match = re.exec(this);
		if(match) {
			var n = parseToken(match,1);
			if(noNames) {
				r.push({name:"",value:n});
			} else {
				var v = parseToken(match,8);
				if(v == null && defaultName) {
					v = n;
					n = defaultName;
				} else if(v == null && defaultValue) {
					v = defaultValue;
				}
				r.push({name:n,value:v});
				if(cascadeDefaults) {
					defaultName = n;
					defaultValue = v;
				}
			}
		}
	} while(match);
	// Summarise parameters into first element
	for(var t=1; t<r.length; t++) {
		if(r[0][r[t].name])
			r[0][r[t].name].push(r[t].value);
		else
			r[0][r[t].name] = [r[t].value];
	}
	return r;
};

// Process a string list of macro parameters into an array. Parameters can be quoted with "", '',
// [[]], {{ }} or left unquoted (and therefore space-separated). Double-braces {{}} results in
// an *evaluated* parameter: e.g. {{config.options.txtUserName}} results in the current user's name.
String.prototype.readMacroParams = function()
{
	var p = this.parseParams("list",null,true,true);
	var n = [];
	for(var t=1; t<p.length; t++)
		n.push(p[t].value);
	return n;
};

// Process a string list of unique tiddler names into an array. Tiddler names that have spaces in them must be [[bracketed]]
String.prototype.readBracketedList = function(unique)
{
	var p = this.parseParams("list",null,false,true);
	var n = [];
	for(var t=1; t<p.length; t++) {
		if(p[t].value)
			n.pushUnique(p[t].value,unique);
	}
	return n;
};

// Returns array with start and end index of chunk between given start and end marker, or undefined.
String.prototype.getChunkRange = function(start,end)
{
	var s = this.indexOf(start);
	if(s != -1) {
		s += start.length;
		var e = this.indexOf(end,s);
		if(e != -1)
			return [s,e];
	}
};

// Replace a chunk of a string given start and end markers
String.prototype.replaceChunk = function(start,end,sub)
{
	var r = this.getChunkRange(start,end);
	return r ? this.substring(0,r[0]) + sub + this.substring(r[1]) : this;
};

// Returns a chunk of a string between start and end markers, or undefined
String.prototype.getChunk = function(start,end)
{
	var r = this.getChunkRange(start,end);
	if(r)
		return this.substring(r[0],r[1]);
};


// Static method to bracket a string with double square brackets if it contains a space
String.encodeTiddlyLink = function(title)
{
	return title.indexOf(" ") == -1 ? title : "[[" + title + "]]";
};

// Static method to encodeTiddlyLink for every item in an array and join them with spaces
String.encodeTiddlyLinkList = function(list)
{
	if(list) {
		var results = [];
		for(var t=0; t<list.length; t++)
			results.push(String.encodeTiddlyLink(list[t]));
		return results.join(" ");
	} else {
		return "";
	}
};

// Convert a string as a sequence of name:"value" pairs into a hashmap
String.prototype.decodeHashMap = function()
{
	var fields = this.parseParams("anon","",false);
	var r = {};
	for(var t=1; t<fields.length; t++)
		r[fields[t].name] = fields[t].value;
	return r;
};

// Static method to encode a hashmap into a name:"value"... string
String.encodeHashMap = function(hashmap)
{
	var r = [];
	for(var t in hashmap)
		r.push(t + ':"' + hashmap[t] + '"');
	return r.join(" ");
};

// Static method to left-pad a string with 0s to a certain width
String.zeroPad = function(n,d)
{
	var s = n.toString();
	if(s.length < d)
		s = "000000000000000000000000000".substr(0,d-s.length) + s;
	return s;
};

String.prototype.startsWith = function(prefix)
{
	return !prefix || this.substring(0,prefix.length) == prefix;
};

// Returns the first value of the given named parameter.
function getParam(params,name,defaultValue)
{
	if(!params)
		return defaultValue;
	var p = params[0][name];
	return p ? p[0] : defaultValue;
}

// Returns the first value of the given boolean named parameter.
function getFlag(params,name,defaultValue)
{
	return !!getParam(params,name,defaultValue);
}

// Substitute date components into a string
Date.prototype.formatString = function(template)
{
	var t = template.replace(/0hh12/g,String.zeroPad(this.getHours12(),2));
	t = t.replace(/hh12/g,this.getHours12());
	t = t.replace(/0hh/g,String.zeroPad(this.getHours(),2));
	t = t.replace(/hh/g,this.getHours());
	t = t.replace(/mmm/g,config.messages.dates.shortMonths[this.getMonth()]);
	t = t.replace(/0mm/g,String.zeroPad(this.getMinutes(),2));
	t = t.replace(/mm/g,this.getMinutes());
	t = t.replace(/0ss/g,String.zeroPad(this.getSeconds(),2));
	t = t.replace(/ss/g,this.getSeconds());
	t = t.replace(/[ap]m/g,this.getAmPm().toLowerCase());
	t = t.replace(/[AP]M/g,this.getAmPm().toUpperCase());
	t = t.replace(/wYYYY/g,this.getYearForWeekNo());
	t = t.replace(/wYY/g,String.zeroPad(this.getYearForWeekNo()-2000,2));
	t = t.replace(/YYYY/g,this.getFullYear());
	t = t.replace(/YY/g,String.zeroPad(this.getFullYear()-2000,2));
	t = t.replace(/MMM/g,config.messages.dates.months[this.getMonth()]);
	t = t.replace(/0MM/g,String.zeroPad(this.getMonth()+1,2));
	t = t.replace(/MM/g,this.getMonth()+1);
	t = t.replace(/0WW/g,String.zeroPad(this.getWeek(),2));
	t = t.replace(/WW/g,this.getWeek());
	t = t.replace(/DDD/g,config.messages.dates.days[this.getDay()]);
	t = t.replace(/ddd/g,config.messages.dates.shortDays[this.getDay()]);
	t = t.replace(/0DD/g,String.zeroPad(this.getDate(),2));
	t = t.replace(/DDth/g,this.getDate()+this.daySuffix());
	t = t.replace(/DD/g,this.getDate());
	var tz = this.getTimezoneOffset();
	var atz = Math.abs(tz);
	t = t.replace(/TZD/g,(tz < 0 ? '+' : '-') + String.zeroPad(Math.floor(atz / 60),2) + ':' + String.zeroPad(atz % 60,2));
	t = t.replace(/\\/g,"");
	return t;
};

Date.prototype.getWeek = function()
{
	var dt = new Date(this.getTime());
	var d = dt.getDay();
	if(d==0) d=7;// JavaScript Sun=0, ISO Sun=7
	dt.setTime(dt.getTime()+(4-d)*86400000);// shift day to Thurs of same week to calculate weekNo
	var n = Math.floor((dt.getTime()-new Date(dt.getFullYear(),0,1)+3600000)/86400000);
	return Math.floor(n/7)+1;
};

Date.prototype.getYearForWeekNo = function()
{
	var dt = new Date(this.getTime());
	var d = dt.getDay();
	if(d==0) d=7;// JavaScript Sun=0, ISO Sun=7
	dt.setTime(dt.getTime()+(4-d)*86400000);// shift day to Thurs of same week
	return dt.getFullYear();
};

Date.prototype.getHours12 = function()
{
	var h = this.getHours();
	return h > 12 ? h-12 : ( h > 0 ? h : 12 );
};

Date.prototype.getAmPm = function()
{
	return this.getHours() >= 12 ? config.messages.dates.pm : config.messages.dates.am;
};

Date.prototype.daySuffix = function()
{
	return config.messages.dates.daySuffixes[this.getDate()-1];
};

// Convert a date to local YYYYMMDDHHMM string format
Date.prototype.convertToLocalYYYYMMDDHHMM = function()
{
	return this.getFullYear() + String.zeroPad(this.getMonth()+1,2) + String.zeroPad(this.getDate(),2) + String.zeroPad(this.getHours(),2) + String.zeroPad(this.getMinutes(),2);
};

// Convert a date to UTC YYYYMMDDHHMM string format
Date.prototype.convertToYYYYMMDDHHMM = function()
{
	return this.getUTCFullYear() + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2);
};

// Convert a date to UTC YYYYMMDD.HHMMSSMMM string format
Date.prototype.convertToYYYYMMDDHHMMSSMMM = function()
{
	return this.getUTCFullYear() + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + "." + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2) + String.zeroPad(this.getUTCSeconds(),2) + String.zeroPad(this.getUTCMilliseconds(),4);
};

// Static method to create a date from a UTC YYYYMMDDHHMM format string
Date.convertFromYYYYMMDDHHMM = function(d)
{
	var hh = d.substr(8,2) || "00";
	var mm = d.substr(10,2) || "00";
	return new Date(Date.UTC(parseInt(d.substr(0,4),10),
			parseInt(d.substr(4,2),10)-1,
			parseInt(d.substr(6,2),10),
			parseInt(hh,10),
			parseInt(mm,10),0,0));
};

//--
//-- RGB colour object
//--

// Construct an RGB colour object from a '#rrggbb', '#rgb' or 'rgb(n,n,n)' string or from separate r,g,b values
function RGB(r,g,b)
{
	this.r = 0;
	this.g = 0;
	this.b = 0;
	if(typeof r == "string") {
		if(r.substr(0,1) == "#") {
			if(r.length == 7) {
				this.r = parseInt(r.substr(1,2),16)/255;
				this.g = parseInt(r.substr(3,2),16)/255;
				this.b = parseInt(r.substr(5,2),16)/255;
			} else {
				this.r = parseInt(r.substr(1,1),16)/15;
				this.g = parseInt(r.substr(2,1),16)/15;
				this.b = parseInt(r.substr(3,1),16)/15;
			}
		} else {
			var rgbPattern = /rgb\s*\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/;
			var c = r.match(rgbPattern);
			if(c) {
				this.r = parseInt(c[1],10)/255;
				this.g = parseInt(c[2],10)/255;
				this.b = parseInt(c[3],10)/255;
			}
		}
	} else {
		this.r = r;
		this.g = g;
		this.b = b;
	}
	return this;
}

// Mixes this colour with another in a specified proportion
// c = other colour to mix
// f = 0..1 where 0 is this colour and 1 is the new colour
// Returns an RGB object
RGB.prototype.mix = function(c,f)
{
	return new RGB(this.r + (c.r-this.r) * f,this.g + (c.g-this.g) * f,this.b + (c.b-this.b) * f);
};

// Return an rgb colour as a #rrggbb format hex string
RGB.prototype.toString = function()
{
	return "#" + ("0" + Math.floor(this.r.clamp(0,1) * 255).toString(16)).right(2) +
				 ("0" + Math.floor(this.g.clamp(0,1) * 255).toString(16)).right(2) +
				 ("0" + Math.floor(this.b.clamp(0,1) * 255).toString(16)).right(2);
};

//--
//-- DOM utilities - many derived from www.quirksmode.org
//--

// Resolve the target object of an event
function resolveTarget(e)
{
	var obj;
	if(e.target)
		obj = e.target;
	else if(e.srcElement)
		obj = e.srcElement;
	if(obj.nodeType == 3) // defeat Safari bug
		obj = obj.parentNode;
	return obj;
}

function drawGradient(place,horiz,locolors,hicolors)
{
	if(!hicolors)
		hicolors = locolors;
	for(var t=0; t<= 100; t+=2) {
		var bar = document.createElement("div");
		place.appendChild(bar);
		bar.style.position = "absolute";
		bar.style.left = horiz ? t + "%" : 0;
		bar.style.top = horiz ? 0 : t + "%";
		bar.style.width = horiz ? (101-t) + "%" : "100%";
		bar.style.height = horiz ? "100%" : (101-t) + "%";
		bar.style.zIndex = -1;
		var p = t/100*(locolors.length-1);
		var hc = hicolors[Math.floor(p)];
		if(typeof hc == "string")
			hc = new RGB(hc);
		var lc = locolors[Math.ceil(p)];
		if(typeof lc == "string")
			lc = new RGB(lc);
		bar.style.backgroundColor = hc.mix(lc,p-Math.floor(p)).toString();
	}
}

function createTiddlyText(parent,text)
{
	return parent.appendChild(document.createTextNode(text));
}

function createTiddlyCheckbox(parent,caption,checked,onChange)
{
	var cb = document.createElement("input");
	cb.setAttribute("type","checkbox");
	cb.onclick = onChange;
	parent.appendChild(cb);
	cb.checked = checked;
	cb.className = "chkOptionInput";
	if(caption)
		wikify(caption,parent);
	return cb;
}

function createTiddlyElement(parent,element,id,className,text,attribs)
{
	var e = document.createElement(element);
	if(className != null)
		e.className = className;
	if(id != null)
		e.setAttribute("id",id);
	if(text != null)
		e.appendChild(document.createTextNode(text));
	if(attribs) {
		for(var n in attribs) {
			e.setAttribute(n,attribs[n]);
		}
	}
	if(parent != null)
		parent.appendChild(e);
	return e;
}

function addEvent(obj,type,fn)
{
	if(obj.attachEvent) {
		obj["e"+type+fn] = fn;
		obj[type+fn] = function(){obj["e"+type+fn](window.event);};
		obj.attachEvent("on"+type,obj[type+fn]);
	} else {
		obj.addEventListener(type,fn,false);
	}
}

function removeEvent(obj,type,fn)
{
	if(obj.detachEvent) {
		obj.detachEvent("on"+type,obj[type+fn]);
		obj[type+fn] = null;
	} else {
		obj.removeEventListener(type,fn,false);
	}
}


// Find the closest relative with a given property value (property defaults to tagName, relative defaults to parentNode)
function findRelated(e,value,name,relative)
{
	name = name || "tagName";
	relative = relative || "parentNode";
	if(name == "className") {
		while(e && !hasClass(e,value)) {
			e = e[relative];
		}
	} else {
		while(e && e[name] != value) {
			e = e[relative];
		}
	}
	return e;
}

// Get the scroll position for window.scrollTo necessary to scroll a given element into view
function ensureVisible(e)
{
	var posTop = findPosY(e);
	var posBot = posTop + e.offsetHeight;
	var winTop = findScrollY();
	var winHeight = findWindowHeight();
	var winBot = winTop + winHeight;
	if(posTop < winTop) {
		return posTop;
	} else if(posBot > winBot) {
		if(e.offsetHeight < winHeight)
			return posTop - (winHeight - e.offsetHeight);
		else
			return posTop;
	} else {
		return winTop;
	}
}

// Get the current width of the display window
function findWindowWidth()
{
	return window.innerWidth || document.documentElement.clientWidth;
}

// Get the current height of the display window
function findWindowHeight()
{
	return window.innerHeight || document.documentElement.clientHeight;
}

// Get the current horizontal page scroll position
function findScrollX()
{
	return window.scrollX || document.documentElement.scrollLeft;
}

// Get the current vertical page scroll position
function findScrollY()
{
	return window.scrollY || document.documentElement.scrollTop;
}

function findPosX(obj)
{
	var curleft = 0;
	while(obj.offsetParent) {
		curleft += obj.offsetLeft;
		obj = obj.offsetParent;
	}
	return curleft;
}

function findPosY(obj)
{
	var curtop = 0;
	while(obj.offsetParent) {
		curtop += obj.offsetTop;
		obj = obj.offsetParent;
	}
	return curtop;
}

// Blur a particular element
function blurElement(e)
{
	if(e && e.focus && e.blur) {
		e.focus();
		e.blur();
	}
}

// Create a non-breaking space
function insertSpacer(place)
{
	var e = document.createTextNode(String.fromCharCode(160));
	if(place)
		place.appendChild(e);
	return e;
}

// Force the browser to do a document reflow when needed to workaround browser bugs
function forceReflow()
{
	if(config.browser.isGecko) {
		setStylesheet("body {top:0px;margin-top:0px;}","forceReflow");
		setTimeout(function() {setStylesheet("","forceReflow");},1);
	}
}

// Replace the current selection of a textarea or text input and scroll it into view
function replaceSelection(e,text)
{
	if(e.setSelectionRange) {
		var oldpos = e.selectionStart;
		var isRange = e.selectionEnd > e.selectionStart;
		e.value = e.value.substr(0,e.selectionStart) + text + e.value.substr(e.selectionEnd);
		e.setSelectionRange(isRange ? oldpos : oldpos + text.length,oldpos + text.length);
		var linecount = e.value.split("\n").length;
		var thisline = e.value.substr(0,e.selectionStart).split("\n").length-1;
		e.scrollTop = Math.floor((thisline - e.rows / 2) * e.scrollHeight / linecount);
	} else if(document.selection) {
		var range = document.selection.createRange();
		if(range.parentElement() == e) {
			var isCollapsed = range.text == "";
			range.text = text;
			if(!isCollapsed) {
				range.moveStart("character", -text.length);
				range.select();
			}
		}
	}
}

// Returns the text of the given (text) node, possibly merging subsequent text nodes
function getNodeText(e)
{
	var t = "";
	while(e && e.nodeName == "#text") {
		t += e.nodeValue;
		e = e.nextSibling;
	}
	return t;
}

// Returns true if the element e has a given ancestor element
function isDescendant(e,ancestor)
{
	while(e) {
		if(e === ancestor)
			return true;
		e = e.parentNode;
	}
	return false;
}


// deprecate the following...

// Prevent an event from bubbling
function stopEvent(e)
{
	var ev = e || window.event;
	ev.cancelBubble = true;
	if(ev.stopPropagation) ev.stopPropagation();
	return false;
}

// Remove any event handlers or non-primitve custom attributes
function scrubNode(e)
{
	if(!config.browser.isIE)
		return;
	var att = e.attributes;
	if(att) {
		for(var t=0; t<att.length; t++) {
			var n = att[t].name;
			if(n !== "style" && (typeof e[n] === "function" || (typeof e[n] === "object" && e[n] != null))) {
				try {
					e[n] = null;
				} catch(ex) {
				}
			}
		}
	}
	var c = e.firstChild;
	while(c) {
		scrubNode(c);
		c = c.nextSibling;
	}
}

function addClass(e,className)
{
	jQuery(e).addClass(className);
}

function removeClass(e,className)
{
	jQuery(e).removeClass(className);
}

function hasClass(e,className)
{
	return jQuery(e).hasClass(className);
}

// Remove all children of a node
function removeChildren(e)
{
	jQuery(e).empty();
}

// Return the content of an element as plain text with no formatting
function getPlainText(e)
{
	return jQuery(e).text();
}

// Remove a node and all it's children
function removeNode(e)
{
	jQuery(e).remove();
}

//--
//-- LoaderBase and SaverBase
//--

function LoaderBase() {}

LoaderBase.prototype.loadTiddler = function(store,node,tiddlers)
{
	var title = this.getTitle(store,node);
	if(safeMode && store.isShadowTiddler(title))
		return;
	if(title) {
		var tiddler = store.createTiddler(title);
		this.internalizeTiddler(store,tiddler,title,node);
		tiddlers.push(tiddler);
	}
};

LoaderBase.prototype.loadTiddlers = function(store,nodes)
{
	var tiddlers = [];
	for(var t = 0; t < nodes.length; t++) {
		try {
			this.loadTiddler(store,nodes[t],tiddlers);
		} catch(ex) {
			showException(ex,config.messages.tiddlerLoadError.format([this.getTitle(store,nodes[t])]));
		}
	}
	return tiddlers;
};

function SaverBase() {}

SaverBase.prototype.externalize = function(store)
{
	var results = [];
	var tiddlers = store.getTiddlers("title");
	for(var t = 0; t < tiddlers.length; t++) {
		if(!tiddlers[t].doNotSave())
			results.push(this.externalizeTiddler(store, tiddlers[t]));
	}
	return results.join("\n");
};

//--
//-- TW21Loader (inherits from LoaderBase)
//--

function TW21Loader() {}

TW21Loader.prototype = new LoaderBase();

TW21Loader.prototype.getTitle = function(store,node)
{
	var title = null;
	if(node.getAttribute) {
		title = node.getAttribute("title");
		if(!title)
			title = node.getAttribute("tiddler");
	}
	if(!title && node.id) {
		var lenPrefix = store.idPrefix.length;
		if(node.id.substr(0,lenPrefix) == store.idPrefix)
			title = node.id.substr(lenPrefix);
	}
	return title;
};

TW21Loader.prototype.internalizeTiddler = function(store,tiddler,title,node)
{
	var e = node.firstChild;
	var text = null;
	if(node.getAttribute("tiddler")) {
		text = getNodeText(e).unescapeLineBreaks();
	} else {
		while(e.nodeName!="PRE" && e.nodeName!="pre") {
			e = e.nextSibling;
		}
		text = e.innerHTML.replace(/\r/mg,"").htmlDecode();
	}
	var modifier = node.getAttribute("modifier");
	var c = node.getAttribute("created");
	var m = node.getAttribute("modified");
	var created = c ? Date.convertFromYYYYMMDDHHMM(c) : version.date;
	var modified = m ? Date.convertFromYYYYMMDDHHMM(m) : created;
	var tags = node.getAttribute("tags");
	var fields = {};
	var attrs = node.attributes;
	for(var i = attrs.length-1; i >= 0; i--) {
		var name = attrs[i].name;
		if(attrs[i].specified && !TiddlyWiki.isStandardField(name)) {
			fields[name] = attrs[i].value.unescapeLineBreaks();
		}
	}
	tiddler.assign(title,text,modifier,modified,tags,created,fields);
	return tiddler;
};

//--
//-- TW21Saver (inherits from SaverBase)
//--

function TW21Saver() {}

TW21Saver.prototype = new SaverBase();

TW21Saver.prototype.externalizeTiddler = function(store,tiddler)
{
	try {
		var extendedAttributes = "";
		var usePre = config.options.chkUsePreForStorage;
		store.forEachField(tiddler,
			function(tiddler,fieldName,value) {
				// don't store stuff from the temp namespace
				if(typeof value != "string")
					value = "";
				if(!fieldName.match(/^temp\./))
					extendedAttributes += ' %0="%1"'.format([fieldName,value.escapeLineBreaks().htmlEncode()]);
			},true);
		var created = tiddler.created;
		var modified = tiddler.modified;
		var attributes = tiddler.modifier ? ' modifier="' + tiddler.modifier.htmlEncode() + '"' : "";
		attributes += (usePre && created == version.date) ? "" :' created="' + created.convertToYYYYMMDDHHMM() + '"';
		attributes += (usePre && modified == created) ? "" : ' modified="' + modified.convertToYYYYMMDDHHMM() +'"';
		var tags = tiddler.getTags();
		if(!usePre || tags)
			attributes += ' tags="' + tags.htmlEncode() + '"';
		return ('<div %0="%1"%2%3>%4</'+'div>').format([
				usePre ? "title" : "tiddler",
				tiddler.title.htmlEncode(),
				attributes,
				extendedAttributes,
				usePre ? "\n<pre>" + tiddler.text.htmlEncode() + "</pre>\n" : tiddler.text.escapeLineBreaks().htmlEncode()
			]);
	} catch (ex) {
		throw exceptionText(ex,config.messages.tiddlerSaveError.format([tiddler.title]));
	}
};

//]]>
</script>
<script id="jsdeprecatedArea" type="text/javascript">
//<![CDATA[
//--
//-- Deprecated Crypto functions and associated conversion routines.
//-- Use the jQuery.encoding functions directly instead.
//--

// Crypto 'namespace'
function Crypto() {}

// Convert a string to an array of big-endian 32-bit words
Crypto.strToBe32s = function(str)
{
	return jQuery.encoding.strToBe32s(str);
};

// Convert an array of big-endian 32-bit words to a string
Crypto.be32sToStr = function(be)
{
	return jQuery.encoding.be32sToStr(be);
};

// Convert an array of big-endian 32-bit words to a hex string
Crypto.be32sToHex = function(be)
{
	return jQuery.encoding.be32sToHex(be);
};

// Return, in hex, the SHA-1 hash of a string
Crypto.hexSha1Str = function(str)
{
	return jQuery.encoding.digests.hexSha1Str(str);
};

// Return the SHA-1 hash of a string
Crypto.sha1Str = function(str)
{
	return jQuery.encoding.digests.sha1Str(str);
};

// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
Crypto.sha1 = function(x,blen)
{
	return jQuery.encoding.digests.sha1(x,blen);
};

//--
//-- Deprecated DOM utilities
//--

// @Deprecated: Use jQuery.stylesheet instead
function setStylesheet(s,id,doc)
{
	jQuery.twStylesheet(s,{ id: id, doc: doc });
}

// @Deprecated: Use jQuery.stylesheet.remove instead
function removeStyleSheet(id)
{
	jQuery.twStylesheet.remove({ id: id });
}
//--
//-- Deprecated HTTP request code
//-- Use the jQuery ajax functions directly instead
//--

function loadRemoteFile(url,callback,params)
{
	return httpReq("GET",url,callback,params);
}

function doHttp(type,url,data,contentType,username,password,callback,params,headers,allowCache)
{
	return httpReq(type,url,callback,params,headers,data,contentType,username,password,allowCache);
}

function httpReq(type,url,callback,params,headers,data,contentType,username,password,allowCache)
{
	var options = {
		type:type,
		url:url,
		processData:false,
		data:data,
		cache:!!allowCache,
		beforeSend: function(xhr) {
			for(var i in headers)
				xhr.setRequestHeader(i,headers[i]);
			xhr.setRequestHeader("X-Requested-With", "TiddlyWiki " + formatVersion());
		}
	};

	if(callback) {
		options.complete = function(xhr,textStatus) {
			if(jQuery.httpSuccess(xhr))
				callback(true,params,xhr.responseText,url,xhr);
			else
				callback(false,params,null,url,xhr);
		};
	}
	if(contentType)
		options.contentType = contentType;
	if(username)
		options.username = username;
	if(password)
		options.password = password;
	if(window.Components && window.netscape && window.netscape.security && document.location.protocol.indexOf("http") == -1)
		window.netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
	jQuery.ajax(options);
}

//--
//-- Deprecated String functions
//--

// @Deprecated: no direct replacement, since not used in core code
String.prototype.toJSONString = function()
{
	// Convert a string to it's JSON representation by encoding control characters, double quotes and backslash. See json.org
	var m = {
		'\b': '\\b',
		'\f': '\\f',
		'\n': '\\n',
		'\r': '\\r',
		'\t': '\\t',
		'"' : '\\"',
		'\\': '\\\\'
		};
	var replaceFn = function(a,b) {
		var c = m[b];
		if(c)
			return c;
		c = b.charCodeAt();
		return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
		};
	if(/["\\\x00-\x1f]/.test(this))
		return '"' + this.replace(/([\x00-\x1f\\"])/g,replaceFn) + '"';
	return '"' + this + '"';
};

//--
//-- Deprecated Tiddler code
//--

// @Deprecated: Use tiddlerToRssItem(tiddler,uri) instead
Tiddler.prototype.toRssItem = function(uri)
{
	return tiddlerToRssItem(this,uri);
};

// @Deprecated: Use "<item>\n" + tiddlerToRssItem(tiddler,uri)  + "\n</item>" instead
Tiddler.prototype.saveToRss = function(uri)
{
	return "<item>\n" + tiddlerToRssItem(this,uri) + "\n</item>";
};

// @Deprecated: Use jQuery.encoding.digests.hexSha1Str instead
Tiddler.prototype.generateFingerprint = function()
{
	return "0x" + Crypto.hexSha1Str(this.text);
};

//]]>
</script>
<script id="jslibArea" type="text/javascript">
//<![CDATA[
/*
 * jQuery JavaScript Library v1.3.2
 * http://jquery.com/
 *
 * Copyright (c) 2009 John Resig
 * Dual licensed under the MIT and GPL licenses.
 * http://docs.jquery.com/License
 *
 * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
 * Revision: 6246
 */
(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof K==="number"){K+=""}return this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G<E;G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return J};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return o},isFunction:function(E){return s.call(E)==="[object Function]"},isArray:function(E){return s.call(E)==="[object Array]"},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){if(G&&/\S/.test(G)){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var E,H=0,I=G.length;if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G)}).join(" "):""}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}return -1},merge:function(H,E){var F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return F},grep:function(F,J,E){var G=[];for(var H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return E.parentNode},parents:function(E){return o.dir(E,"parentNode")},next:function(E){return o.nth(E,2,"nextSibling")},prev:function(E){return o.nth(E,2,"previousSibling")},nextAll:function(E){return o.dir(E,"nextSibling")},prevAll:function(E){return o.dir(E,"previousSibling")},siblings:function(E){return o.sibling(E.parentNode.firstChild,E)},children:function(E){return o.sibling(E.firstChild)},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var J=[],L=o(G);for(var K=0,H=L.length;K<H;K++){var I=(K>0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}});
/*
 * Sizzle CSS Selector Engine - v0.9.3
 *  Copyright 2009, The Dojo Foundation
 *  Released under the MIT, BSD, and GPL Licenses.
 *  More information: http://sizzlejs.com/
 */
(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML='   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})();
//]]>
</script>
<script id="jqueryArea" type="text/javascript">
//<![CDATA[
/*
jQuery.encoding.digests.sha1.js

SHA-1 digest and associated utility functions

Copyright (c) UnaMesa Association 2009

Dual licensed under the MIT and GPL licenses:
  http://www.opensource.org/licenses/mit-license.php
  http://www.gnu.org/licenses/gpl.html
*/

(function($) {

if(!$.encoding)
	$.encoding = {};
	$.extend($.encoding,{
		strToBe32s: function(str) {
			// Convert a string to an array of big-endian 32-bit words
			var be=[];
			var len=Math.floor(str.length/4);
			var i, j;
			for(i=0, j=0; i<len; i++, j+=4) {
				be[i]=((str.charCodeAt(j)&0xff) << 24)|((str.charCodeAt(j+1)&0xff) << 16)|((str.charCodeAt(j+2)&0xff) << 8)|(str.charCodeAt(j+3)&0xff);
			}
			while(j<str.length) {
				be[j>>2] |= (str.charCodeAt(j)&0xff)<<(24-(j*8)%32);
				j++;
			}
			return be;
		},
		be32sToStr: function(be) {
			// Convert an array of big-endian 32-bit words to a string
			var str='';
			for(var i=0;i<be.length*32;i+=8) {
				str += String.fromCharCode((be[i>>5]>>>(24-i%32)) & 0xff);
			}
			return str;
		},
		be32sToHex: function(be) {
			// Convert an array of big-endian 32-bit words to a hex string
			var hex='0123456789ABCDEF';
			var str='';
			for(var i=0;i<be.length*4;i++) {
				str += hex.charAt((be[i>>2]>>((3-i%4)*8+4))&0xF) + hex.charAt((be[i>>2]>>((3-i%4)*8))&0xF);
			}
			return str;
		}
	});
})(jQuery);


(function($) {

if(!$.encoding.digests)
	$.encoding.digests = {};
	$.extend($.encoding.digests,{
		hexSha1Str: function(str) {
			// Return, in hex, the SHA-1 hash of a string
			return $.encoding.be32sToHex($.encoding.digests.sha1Str(str));
		},
		sha1Str: function(str) {
			// Return the SHA-1 hash of a string
			return sha1($.encoding.strToBe32s(str),str.length);
		},
		sha1: function(x,blen) {
			// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
			return sha1($.encoding.strToBe32s(str),str.length);
		}
	});

	// Private functions.
	function sha1(x,blen) {
		// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
		function add32(a,b) {
			// Add 32-bit integers, wrapping at 32 bits
			// Uses 16-bit operations internally to work around bugs in some JavaScript interpreters.
			var lsw=(a&0xFFFF)+(b&0xFFFF);
			var msw=(a>>16)+(b>>16)+(lsw>>16);
			return (msw<<16)|(lsw&0xFFFF);
		}
		function AA(a,b,c,d,e) {
			// Cryptographic round helper function. Add five 32-bit integers, wrapping at 32 bits, second parameter is rotated left 5 bits before the addition
			// Uses 16-bit operations internally to work around bugs in some JavaScript interpreters.
			b=(b>>>27)|(b<<5);
			var lsw=(a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF);
			var msw=(a>>16)+(b>>16)+(c>>16)+(d>>16)+(e>>16)+(lsw>>16);
			return (msw<<16)|(lsw&0xFFFF);
		}
		function RR(w,j) {
			// Cryptographic round helper function.
			var n=w[j-3]^w[j-8]^w[j-14]^w[j-16];
			return (n>>>31)|(n<<1);
		}

		var len=blen*8;
		x[len>>5] |= 0x80 << (24-len%32);
		x[((len+64>>9)<<4)+15]=len;
		var w=new Array(80);

		var k1=0x5A827999;
		var k2=0x6ED9EBA1;
		var k3=0x8F1BBCDC;
		var k4=0xCA62C1D6;

		var h0=0x67452301;
		var h1=0xEFCDAB89;
		var h2=0x98BADCFE;
		var h3=0x10325476;
		var h4=0xC3D2E1F0;

		for(var i=0;i<x.length;i+=16) {
			var j=0;
			var t;
			var a=h0;
			var b=h1;
			var c=h2;
			var d=h3;
			var e=h4;
			while(j<16) {
				w[j]=x[i+j];
				t=AA(e,a,d^(b&(c^d)),w[j],k1);
				e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
			}
			while(j<20) {
				w[j]=RR(w,j);
				t=AA(e,a,d^(b&(c^d)),w[j],k1);
				e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
			}
			while(j<40) {
				w[j]=RR(w,j);
				t=AA(e,a,b^c^d,w[j],k2);
				e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
			}
			while(j<60) {
				w[j]=RR(w,j);
				t=AA(e,a,(b&c)|(d&(b|c)),w[j],k3);
				e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
			}
			while(j<80) {
				w[j]=RR(w,j);
				t=AA(e,a,b^c^d,w[j],k4);
				e=d; d=c; c=(b>>>2)|(b<<30); b=a; a=t; j++;
			}
			h0=add32(h0,a);
			h1=add32(h1,b);
			h2=add32(h2,c);
			h3=add32(h3,d);
			h4=add32(h4,e);
		}
		return [h0,h1,h2,h3,h4];
	}
})(jQuery);
/*
jQuery.twStylesheet.js

jQuery plugin to dynamically insert CSS rules into a document

Usage:
  jQuery.twStylesheet applies style definitions
  jQuery.twStylesheet.remove neutralizes style definitions

Copyright (c) UnaMesa Association 2009

Triple licensed under the BSD, MIT and GPL licenses:
  http://www.opensource.org/licenses/bsd-license.php
  http://www.opensource.org/licenses/mit-license.php
  http://www.gnu.org/licenses/gpl.html
*/

(function($) {

var defaultId = "customStyleSheet"; // XXX: rename to dynamicStyleSheet?

// Add or replace a style sheet
// css argument is a string of CSS rule sets
// options.id is an optional name identifying the style sheet
// options.doc is an optional document reference
// N.B.: Uses DOM methods instead of jQuery to ensure cross-browser comaptibility.
$.twStylesheet = function(css, options) {
	options = options || {};
	var id = options.id || defaultId;
	var doc = options.doc || document;
	var el = doc.getElementById(id);
	if(doc.createStyleSheet) { // IE-specific handling
		if(el) {
			el.parentNode.removeChild(el);
		}
		doc.getElementsByTagName("head")[0].insertAdjacentHTML("beforeEnd",
			"&nbsp;<style id='" + id + "'>" + css + "</style>"); // fails without &nbsp;
	} else { // modern browsers
		if(el) {
			el.replaceChild(doc.createTextNode(css), el.firstChild);
		} else {
			el = doc.createElement("style");
			el.type = "text/css";
			el.id = id;
			el.appendChild(doc.createTextNode(css));
			doc.getElementsByTagName("head")[0].appendChild(el);
		}
	}
};

// Remove existing style sheet
// options.id is an optional name identifying the style sheet
// options.doc is an optional document reference
$.twStylesheet.remove = function(options) {
	options = options || {};
	var id = options.id || defaultId;
	var doc = options.doc || document;
	var el = doc.getElementById(id);
	if(el) {
		el.parentNode.removeChild(el);
	}
};

})(jQuery);
//]]>
</script>
<script type="text/javascript">
//<![CDATA[
if(useJavaSaver)
	document.write("<applet style='position:absolute;left:-1px' name='TiddlySaver' code='TiddlySaver.class' archive='TiddlySaver.jar' width='1' height='1'></applet>");
//]]>
</script>
<!--POST-SCRIPT-START-->

<!--POST-SCRIPT-END-->
</body>
</html>
